Client side Blazor: Slow load of a resource - c#

I have some lines of code, that worked well in Xamarin.Forms, but it performs very poorly in Client-side Blazor.
This is the code:
string s = System.Text.Encoding.UTF8.GetString(Properties.Resources.city_list);
List _cityList = JsonConvert.DeserializeObject<List>(s).ToList();
the city_list is a huge list from OpenWeatherMap that is containing all the cities around the globe.
Later I want to display this list as options in a select, so I would like to keep it on the client-side. The code now is very slow, it takes minutes to run it. Do you have an idea, how can I make it faster?
Thank you in advance
Janos
Update:
I removed the Take(20), because that is not part of the problem. I want to get the full list.
The city_list is a text file in Json format. I added it as Resource, so it is a byte array in this code.

This problem is related to very slow string parsing in Blazor. Yesterday I hit the same problem with parsing a json data of 6 mb. Even with the small json data the delays between page landings are noticable to eye. In a non-Blazor .NET application parsing is done really fast though.
So I figured out whether the problem is about json parsing or in general string parsing. I tested the below code on a reguler Console app and on Blazor WebAssembly. The difference is huge: Console(768 milliseconds), Blazor 45(seconds). Seems like this is an issue with web assembly because javascript parsing is also fast. This problem has been around for sometime. See also here.
https://github.com/dotnet/runtime/issues/40386
Well this being said even though this is a very simple problem it completely invalidates Blazor as a production ready framework.
This was tested on .NET 6 both for Console and Blazor.
public class StringParsePerfTest
{
private string Text { get; set; } = "";
public StringParsePerfTest()
{
for(int i = 0; i < 10000; i++)
{
if (i % 3 == 0) Text += "|";
else Text += "a";
}
}
public void Test()
{
var start = DateTime.Now;
start= DateTime.Now;
for(int i = 0; i < 10000; i++)
{
var splitted = Text.Split("|");
}
var end = DateTime.Now;
Console.WriteLine($"{(end - start).TotalMilliseconds}");
}
}

Related

Saving streamed Data from Unity in a csv File

I have to record the coordinate-data (vector of x,y,z) of an eye-tracking System and save it, for later evaluation. The whole eye-tracking System is integrated inside a Head-mounted-Display and the software runs over Unity.
After some research, I figured out that saving the Data in a CSV file would probably the easiest way. This is what I got so far:
void update()
{
string filePath = #"C:\Data.csv";
string delimiter = ",";
Vector3 leftGazeDirection = smiInstance.smi_GetLeftGazeDirection();
Vector3 rightGazeDirection = smiInstance.smi_GetRightGazeDirection();
float[][] output = new float[][]{
new float[]{leftGazeDirection.x},
new float[]{leftGazeDirection.y},
new float[]{leftGazeDirection.z},
new float[]{rightGazeDirection.x},
new float[]{rightGazeDirection.y},
new float[]{rightGazeDirection.z} };
int length = output.GetLength(0);
StringBuilder sb = new StringBuilder();
for (int index = 0; index < length; index++)
sb.AppendLine(string.Join(delimiter, output[index]));
File.WriteAllText(#"C:\Data.csv", sb.ToString());
}
What this gives me out is a CSV file with the Vector of the latest Position of the Gazedirection. What I need would be a Record of all the Gazedirections that were made in one Session. Is it possible to get something like this?
Can I somehow modify my Code to achieve this or should I try something completely different?
Since I'm very newbie to unity and programming in general I just have a lack of vocabulary and don't know what to search for to solve my problem..
I would be very thankful if somebody could help me. :)
Welcome to StackOverflow. A good question, and well set out.
Presumably after you save this data away, you want to do something with it. I would suggest that your life is going to be a lot easier if you were to create a database to store your data. There are tons of tutorials on this sort of thing, and since you are already writing in C# it should not be too hard for you.
I would be creating a SQL Server database - either the Express version or Developer Version, both would be free for you.
I would steer away from trying Entity Framework or similar at this stage, I would just use the basic SQLClient to connect and write to your database.
Once you start using this then adding something like a Session column to separate one session from the next becomes easy, and all sorts of analysis you might want to do onthe data will also become much easier.
Hope this helps, and good luck with your project.
Yes. You can have data for one entire session. Look no further than File.AppendAllText. In this scenario I'm assuming that you have 6 values for two gaze pointers. In that case you don't need to write it down as multidimensional array as it is just wasting allocated memory.
Here we can proceed to save it as 6 values for each iteration of your loop.
string filePath = #"C:\Data.csv";
string delimiter = ",";
void Start()
{
if(File.Exists(filePath))
File.Delete(filePath);
}
void Update
{
Vector3 leftGazeDirection = smiInstance.smi_GetLeftGazeDirection();
Vector3 rightGazeDirection = smiInstance.smi_GetRightGazeDirection();
float[] output = new float[]{
leftGazeDirection.x,
leftGazeDirection.y,
leftGazeDirection.z,
rightGazeDirection.x,
rightGazeDirection.y,
rightGazeDirection.z };
int length = output.Length;
StringBuilder sb = new StringBuilder();
for (int index = 0; index < length; index++)
sb.AppendLine(output[index],delimiter));
if(!File.Exists(filePath))
File.WriteAllText(filePath, sb.ToString());
else
File.AppendAllText(filePath, sb.ToString());
}
AppendAllText will keep on appending file till the end of execution. Note that this solution has downside that is at the start we will delete the file for each session so you will need to manually keep track of each session.
So if you want to keep a bunch of files related to each session and not to overrride the same file we can include the date and time stamp while creating each file. So instead of deleting old file for each new session we are creating file for each session and writing in it. Only start method will need to change to handle datetime stamp for file name appending. Rest of the Update loop will be same.
string filePath = #"C:\Data";
string delimiter = ",";
void Start()
{
filePath = filePath + DateTime.Now.ToString("yyyy-mm-dd-hh-mm-ss") + ".csv";
}

How to find the other part of a string

I'm trying to make C# program that gets a line on a website and use it.
Unfortunately, I don't know the full line on the site. I only know "steam://joinlobby/730/". Although, what comes after "/730/" is always different.
So i need help getting the full line that comes after it.
What I've got:
public void Main()
{
WebClient web = new WebClient();
// here is the site that i want to download and read text from it.
string result = web.DownloadString("http://steamcommunity.com/id/peppahtank");
if (result.Contains("steam://joinlobby/730/"))
{
//get the part after /730/
}
}
I can tell you that it always ends with "xxxxxxxxxxxxxxxxx/xxxxxxxxxxxxxxxxxx"
so: steam://joinlobby/730/xxxxxxxxx/xxxxxxxx.
What's to prevent you from just splitting the string on '/730/'?
result.Split(#"/730/")[1]
https://msdn.microsoft.com/en-us/library/system.string.split(v=vs.110).aspx
The easiest method for this particular case would be to take the first part, and then just skip that many characters
const string Prefix = #"steam://joinlobby/730/";
//...
if(result.StartsWith(Prefix))
{
var otherPart = result.SubString(Prefix.Length);
// TODO: Process other part
}
Make sure your result is not null and begins with steam://joinlobby/730/
if(string.IsNullOrWhiteSpaces(result) && result.StartsWith("steam://joinlobby/730/"))
{
string rest = result.SubString(("steam://joinlobby/730/").Length);
}

Delving into the world of XML (Windows Phone) Error I dont understand (The ' ' character, hexadecimal value 0x20, cannot be included in a name.)

So I am starting to learn how to use XML data within a app and decided to use some free data to do this however I cannot for the life of me get it working this is my code so far. (I have done a few apps with static data before but hey apps are designed to use the web right? :p)
public partial class MainPage : PhoneApplicationPage
{
List<XmlItem> xmlItems = new List<XmlItem>();
// Constructor
public MainPage()
{
InitializeComponent();
LoadXmlItems("http://hatrafficinfo.dft.gov.uk/feeds/datex/England/CurrentRoadworks/content.xml");
test();
}
public void test()
{
foreach (XmlItem item in xmlItems)
{
testing.Text = item.Title;
}
}
public void LoadXmlItems(string xmlUrl)
{
WebClient client = new WebClient();
client.OpenReadCompleted += (sender, e) =>
{
if (e.Error != null)
return;
Stream str = e.Result;
XDocument xdoc = XDocument.Load(str);
***xmlItems = (from item in xdoc.Descendants("situation id")
select new XmlItem()
{
Title = item.Element("impactOnTraffic").Value,
Description = item.Element("trafficRestrictionType").Value
}).ToList();***
// close
str.Close();
// add results to the list
xmlItems.Clear();
foreach (XmlItem item in xmlItems)
{
xmlItems.Add(item);
}
};
client.OpenReadAsync(new Uri(xmlUrl, UriKind.Absolute));
}
}
I am basically trying to learn how to do this at the moment as I am intrigued how to actually do it (I know there are many ways but ATM this way seems the easiest) I just don't get what the error is ATM. (The bit in * is where it says the error is)
I also know the display function ATM is not great (As it will only show the last item) but for testing this will do for now.
To some this may seem easy, as a learner its not so easy for me just yet.
The error in picture form:
(It seems I cant post images :/)
Thanks in advance for the help
Edit:
Answer below fixed the error :D
However still nothing is coming up. I "think" it's because of the XML layout and the amount of descendants it has (Cant work out what I need to do being a noob at XML and pulling it from the web as a data source)
Maybe I am starting too complicated :/
Still any help/tips on how to pull some elements from the feed (As there all in Descendants) correctly and store them would be great :D
Edit2:
I have it working (In a crude way) but still :D
Thanks Adam Maras!
The last issue was the double listing. (Adding it to a list, to then add it to another list was causing a null exception) Just using the 1 list within the method solved this issue, (Probably not the best way of doing it but it works for now) and allowed for me to add the results to a listbox until I spend some time working out how to use ListBox.ItemTemplate & DataTemplate to make it look more appealing. (Seems easy enough I say now...)
Thanks Again!!!
from item in xdoc.Descendants("situation id")
// ^
XML tag names can't contain spaces. Looking at the XML, you probably just want "situation" to match the <situation> elements.
After looking at your edit and further reviewing the XML, I figured out what the problem is. If you look at the root element of the document:
<d2LogicalModel xmlns="http://datex2.eu/schema/1_0/1_0" modelBaseVersion="1.0">
You'll see that it has a default namespace applied. The easiest solution to your problem will be to first get the namespsace from the root element:
var ns = xdoc.Root.Name.Namespace;
And then apply it wherever you're using a string to identify an element or attribute name:
from item in xdoc.Descendants(ns + "situation")
// ...
item.Element(ns + "impactOnTraffic").Value
item.Element(ns + "trafficRestrictionType").Value
One more thing: <impactOnTraffic> and <trafficRestrictionType> aren't direct children of the <situation> element, so you'll need to change that code as well:
Title = items.Descendants(ns + "impactOnTraffic").Single().Value,
Description = item.Descendants(ns + "trafficRestrictionType").Single().Value

Can i Read code from a file and and let that code run in an application

I am developing an Desktop Application in WPF using C# .
For the sake of simplicity, Assume my Application has functions which draw lines in said direction goleft() , goright() , goforward() , goback() .
when any of these function is called a line of one inch will be drawn on screen.
I want to make application where user will write code in a file in any editor (say notepad) and save that file in some fixed format (say .abc or .xyz)
Imaginary Example :
(section_start)
For(int i = 0 ; i<= 20 ; i++ )
{
if(i<5)
goforward();
else if(i==5)
goleft();
else if(i < 10)
forward();
.......
........
}
(section_End)
Can i make application which should be capable of reading this file and execute code which is written in between of (section_start) and (section_End). and only if possible can check for syntax errors too... (Not compulsory).
Please guide me on this issue :
Disclosure : My actual Application is somewhat else and could not discuss here due to my company's rules.
Thanks to all who replied to my question. Stackoverflow is fantastic site , i have found the roadmap where to go , till today morning i did not have any clue but now i can go ahead , thanks all of you once again
Will ask question again if i get stucked somewhere
You can read the file content using FileInfo and get the code you need to execute.
Then you can execute the code using CSharpCodeProvider like in this post:
using (Microsoft.CSharp.CSharpCodeProvider foo =
new Microsoft.CSharp.CSharpCodeProvider())
{
var res = foo.CompileAssemblyFromSource(
new System.CodeDom.Compiler.CompilerParameters()
{
GenerateInMemory = true
},
"public class FooClass { public string Execute() { return \"output!\";}}"
);
var type = res.CompiledAssembly.GetType("FooClass");
var obj = Activator.CreateInstance(type);
var output = type.GetMethod("Execute").Invoke(obj, new object[] { });
}
You can choose CodeDOM or IL Emit
More help on CodeDOM
More information on IL Generator / Emit
This is called scripting your application if I understand correctly. C# does not support this out of the box. One thing to look into could be the new Roselyn compiler from Microsoft (it is a new take on the C# compiler, which lets you do just this).
For more info on Roselyn check out:
http://blogs.msdn.com/b/csharpfaq/archive/2011/12/02/introduction-to-the-roslyn-scripting-api.aspx
I've only seen a demo of it, but it looks very promissing, and should solve your problem.
It's not clear what kind of code you want compiled but here is a guide on how to compile code code with C#.
You could use IronPython to handle the script.
Here's an example of how to do this:
First you need a navigation object to perform the operations on:
public class NavigationObject
{
public int Offset { get; private set; }
public void GoForwards()
{
Offset++;
}
public void GoBackwards()
{
Offset--;
}
}
Then the code to execute the file:
public void RunNavigationScript(string filePath, NavigationObject navObject)
{
var engine = Python.CreateEngine();
var scope = engine.CreateScope();
scope.SetVariable("navigation", navObject);
var source = engine.CreateScriptSourceFromFile(filePath);
try
{
source.Execute(scope);
}
catch(Exception
{
}
}
The script file can then take the form of something like:
for x in range(0,20):
if x == 5:
navigation.GoBackwards()
else:
navigation.GoForwards()

Html parser to get blog posts

I need to create a html parser, that given a blog url, it returns a list, with all the posts in the page.
I.e. if a page has 10 posts, it
should return a list of 10 divs,
where each div contains h1 and
a p
I can't use its rss feed, because I need to know exactly how it looks like for the user, if it has any ad, image etc and in contrast some blogs have just a summary of its content and the feed has it all, and vice-versa.
Anyway, I've made one that download its feed, and search the html for similar content, it works very well for some blogs, but not for others.
I don't think I can make a parser that works for 100% of the blogs it parses, but I want to make the best possible.
What should be the best approach? Look for tags that have its id attribute equal "post", "content"? Look for p tags? etc etc etc...
Thanks in advance for any help!
I don't think you will be successful on that. You might be able to parse one blog, but if the blog engine changes stuff, it won't work any more. I also don't think you'll be able to write a generic parser. You might even be partially successful, but it's going to be an ethereal success, because everything is so error prone on this context. If you need content, you should go with RSS. If you need to store (simply store) how it looks, you can also do that. But parsing by the way it looks? I don't see concrete success on that.
"Best possible" turns out to be "best reasonable," and you get to define what is reasonable. You can get a very large number of blogs by looking at how common blogging tools (WordPress, LiveJournal, etc.) generate their pages, and code specially for each one.
The general case turns out to be a very hard problem because every blogging tool has its own format. You might be able to infer things using "standard" identifiers like "post", "content", etc., but it's doubtful.
You'll also have difficulty with ads. A lot of ads are generated with JavaScript. So downloading the page will give you just the JavaScript code rather than the HTML that gets generated. If you really want to identify the ads, you'll have to identify the JavaScript code that generates them. Or, your program will have to execute the JavaScript to create the final DOM. And then you're faced with a problem similar to that above: figuring out if some particular bit of HTML is an ad.
There are heuristic methods that are somewhat successful. Check out Identifying a Page's Primary Content for answers to a similar question.
Use the HTML Agility pack. It is an HTML parser made for this.
I just did something like this for our company's blog which uses wordpress. This is good for us because our wordress blog hasn't changed in years, but the others are right in that if your html changes a lot, parsing becomes a cumbersome solution.
Here is what I recommend:
Using Nuget install RestSharp and HtmlAgilityPack. Then download fizzler and include those references in your project (http://code.google.com/p/fizzler/downloads/list).
Here is some sample code I used to implement the blog's search on my site.
using System;
using System.Collections.Generic;
using Fizzler.Systems.HtmlAgilityPack;
using RestSharp;
using RestSharp.Contrib;
namespace BlogSearch
{
public class BlogSearcher
{
const string Site = "http://yourblog.com";
public static List<SearchResult> Get(string searchTerms, int count=10)
{
var searchResults = new List<SearchResult>();
var client = new RestSharp.RestClient(Site);
//note 10 is the page size for the search results
var pages = (int)Math.Ceiling((double)count/10);
for (int page = 1; page <= pages; page++)
{
var request = new RestSharp.RestRequest
{
Method = Method.GET,
//the part after .com/
Resource = "page/" + page
};
//Your search params here
request.AddParameter("s", HttpUtility.UrlEncode(searchTerms));
var res = client.Execute(request);
searchResults.AddRange(ParseHtml(res.Content));
}
return searchResults;
}
public static List<SearchResult> ParseHtml(string html)
{
var doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(html);
var results = doc.DocumentNode.QuerySelectorAll("#content-main > div");
var searchResults = new List<SearchResult>();
foreach(var node in results)
{
bool add = false;
var sr = new SearchResult();
var a = node.QuerySelector(".posttitle > h2 > a");
if (a != null)
{
add = true;
sr.Title = a.InnerText;
sr.Link = a.Attributes["href"].Value;
}
var p = node.QuerySelector(".entry > p");
if (p != null)
{
add = true;
sr.Exceprt = p.InnerText;
}
if(add)
searchResults.Add(sr);
}
return searchResults;
}
}
public class SearchResult
{
public string Title { get; set; }
public string Link { get; set; }
public string Exceprt { get; set; }
}
}
Good luck,
Eric

Categories