Background
I am working on an application that requires the consumption of JSON services on the server, and then repackaging of that JSON into a view model that can be referenced using Razor syntax in the view. Server-side manipulation of this code is a must for various reasons.
We are using C#, .NET 4, MVC3, Razor, JsonFx.
We currently have code that works just fine, but it is taking up to a minute to iterate 250 items in the received JSON object and this is unacceptable (not to mention baffling). I have already isolated the problem to the following loop; the JSON comes in lightening-fast so that is not the problem. Here is the working but extremely slow code:
var reader = new JsonReader();
var json = GetJson(SPListName);
var admItems = new List<IDictionary<String, object>>();
dynamic _items = reader.Read(json); //This part is REALLY fast. No problem here.
foreach (var itm in _items)
{
dynamic obj = new ExpandoObject();
foreach (dynamic admObj in itm)//Here begins the slow part.
{
var item = obj as IDictionary<String, object>;
var encodedValue = "";
try
{
if(admObj.Key == "Title")
{
encodedValue = admObj.Value.ToString();
}else
{
encodedValue = admObj.Value[0].ToString();
}
}
catch (Exception)
{
encodedValue = admObj.Value.ToString();
}
item[admObj.Key] = encodedValue.EncodeNonAscii().FixHtmlEntities();
}
admItems.Add(obj);
}
return admItems;
You may also notice a few custom extension methods. Here they are (in case that matters):
public static string EncodeNonAscii(this Object str)
{
StringBuilder sb = new StringBuilder();
foreach (char c in str.ToString())
{
if (c > 127)
{
// This character is too big for ASCII
string encodedValue = "\\u" + ((int) c).ToString("x4");
sb.Append(encodedValue);
}
else
{
sb.Append(c);
}
}
return sb.ToString();
}
public static string FixHtmlEntities(this Object str)
{
var fixedString = str.ToString().Replace("\\u00c2\\u00ae", "®");
return fixedString;
}
Question
What the heck am I doing wrong/how do I speed this up. My brain is hamburger right now so I hope someone points out a simple oversight.
Update/Resolution
Rophuine and Joshua Enfield both pointed to the root of the speed issue: the catching of exceptions was slowing everything down.
Many folks suggested that I use Json.Net or something similar. While I appreciate that advice, it really wasn't at the root of my problem (even though it may have appeared that way); I have used Json.Net extensively in the past and came to prefer JsonFx over it a few months ago. In this particular case, I am more concerned with the construction of a view model object as I have already deserialized the JSON using JsonFx. Please let me know if you still think I am missing your point ;).
The reason for my brain-dead try/catch scheme was that I needed to do different things with each property of the JSON string depending on it's type (string, string[], object[], etc). I forgot that System.Type can handle that for me. So here is the final code:
var reader = new JsonReader();
var json = GetJson(SPListName);
var admItems = new List<IDictionary<String, object>>();
dynamic _items = reader.Read(json);
foreach (var itm in _items)
{
dynamic obj = new ExpandoObject();
foreach (dynamic admObj in itm)
{
var item = obj as IDictionary<String, object>;
var encodedValue = "";
Type typeName = admObj.Value.GetType();
switch (typeName.ToString())
{
case("System.String[]"):
encodedValue = admObj.Value[0].ToString();
break;
default:
encodedValue = admObj.Value.ToString();
break;
}
item[admObj.Key] = encodedValue.EncodeNonAscii().FixHtmlEntities();
}
admItems.Add(obj);
}
return admItems;
Hope this helps someone!