Solving “No parameterless constructor defined for type of ‘System.String’.”
TL;DR
If you have the problem
No parameterless constructor defined for type of ‘System.String’!
just add the DeserializeObject and InterceptError functions , add this 2 lines:
var obj = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(json); //json parameter is the string content of the api <your object> = DeserializeObject(obj, typeof(<your object type>)) as <your object type>;
watch the debug window and you will see the problems marked with !!!
( See also video at http://youtu.be/7oZ37pnSNtM)
Long story:
I wanted to do a tutorial for obtaining data from foursquare from Web , Desktop and mobile applications. I have made some research first and I have discovered the API and a library for obtaining data.
Unfortunately, foursquare changed his API and , when deserializing, the application was giving
“No parameterless constructor defined for type of ‘System.String’.
at this line
fourSquareResponse = new JavaScriptSerializer().Deserialize<FourSquareSingleResponse<T>>(json);
I have made a custom code to see where the errors are.
I do not want to explain the code, just look at it and then I will show how to use:
/// <summary> /// TODO: make this add to global errors to return to the caller /// </summary> /// <param name="message"></param> private void InterceptError(string message) { var cc = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(message); Console.ForegroundColor = cc; Debug.WriteLine(message); } private object DeserializeObject(Dictionary<string, object> dictItem, Type tip) { var newInstance = Activator.CreateInstance(tip); var isDictionary = (tip.GetInterface("IDictionary") != null); PropertyInfo p = null; foreach (var k in dictItem.Keys) { var ser= new JavaScriptSerializer().Serialize(dictItem[k]); Type tipP = null; if (isDictionary) { tipP = tip.GetGenericArguments()[1]; } else { try { p = tip.GetProperty(k); if (p == null) throw new ArgumentNullException(k); } catch (Exception) { //Console.WriteLine(ex.Message); InterceptError("missing property:" + k + " to class" + tip.FullName + " value:" + ser); continue; } tipP = p.PropertyType; } if (tipP.IsClass && tipP.FullName != typeof(string).FullName) { dynamic val = null; try { val = new JavaScriptSerializer().Deserialize(ser, tipP); } catch (Exception ex) { Console.WriteLine("error for class:" + k + ex.Message); IList arr = dictItem[k] as object[]; if (arr == null) { arr = dictItem[k] as ArrayList; } if (arr == null) { var t1 = dictItem[k] as Dictionary<string, object>; if (t1 == null) { InterceptError("Not a dictionary, not an array - please contact ignatandrei@yahoo.com for " + k); } val = DeserializeObject(dictItem[k] as Dictionary<string, object>, tipP); } else { val = Activator.CreateInstance(tipP); var tipGen=tipP.GetGenericArguments()[0]; foreach (var obj in arr) { val.Add((dynamic)DeserializeObject(obj as Dictionary<string, object>, tipGen)); } } } if (isDictionary) { ((IDictionary)newInstance).Add(k, Convert.ChangeType(val, tipP)); } else { p.SetValue(newInstance, Convert.ChangeType(val, tipP), null); } } else//simple int , string, { try { if (isDictionary) { ((IDictionary)newInstance).Add(k, Convert.ChangeType(dictItem[k], tipP)); } else { p.SetValue(newInstance, Convert.ChangeType(dictItem[k], tipP), null); } } catch (Exception ex) { InterceptError("!!!not a simple property " + k + " from " + tip + " value:" + ser); } } } return newInstance; }
Now the original code that throws the error looks this way:
try { fourSquareResponse = new JavaScriptSerializer().Deserialize<FourSquareSingleResponse<T>>(json); //json parameter is the string content of the api } catch (Exception ex) { var obj = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(json); //json parameter is the string content of the api fourSquareResponse = DeserializeObject(obj, typeof(FourSquareSingleResponse<T>)) as FourSquareSingleResponse<T>; }
When looking to the debug window, you will see:
!!!not a simple property icon from FourSquare.SharpSquare.Entities.Category value:{"prefix":"https://ss1.4sqi.net/img/categories_v2/building/home_","suffix":".png"}
If looking to the source code, you will see
public string icon { get; set; }
And in the foursquare api you will see
- icon: {
- prefix: "https://ss1.4sqi.net/img/categories_v2/travel/trainstation_"
- suffix: ".png"
}
Now it is clear : icon is not a string, is a class!
So just add a class with required properties , modify the property from string to this class and it is all solved!
( for me, the class is:
public class Icon { public string prefix { get; set; } public string suffix { get; set; } }
and the definition will be:
public Icon icon { get; set; }
Moral of the story:
When obtaining data via HTTP API, just be sure that you can handle modifications!
I would say that this is a problem with FourSquare web service, that introduced a breaking change in their API..
It can be same problem with any other webservice that introduces a breaking change 😉
Hi there! I just wanted to say that your code to help debug the deserialization issue REALLY helped me today. I’m working with nested objects and it was nearly impossible to find the issue otherwise. Thanks so much for posting it!
First of all, thanks for the code. It is a rather remarkable piece of engineering.
I thought I might add some helpful information/hints for others who might want to take advantage of your code …
First, with regards to how it works, as I understand it, this is a recursive procedure that walks through the JSON tree structure and compares it against the supplied JSON object model (the “Type” in the parameter list). Where it finds discrepancies between the two, it changes the JSON object model on-the-fly to conform to the supplied JSON.
In doing this processing, it makes use of reflection. So, it is slower than the standard deserialization approach (i.e., what one does in “try{}”). That is the reason why one should try the standard deserialization approach. However, it does allow the JSON object to be loaded.
Now, if one is going to utilize a section of the JSON that might have been changed, that could be a problem. In other instances (specifically mine), that errant section is ignored; thus changing it to allow the JSON to be loaded is all to the good.
With regards to “breaking changes”, the “breaking change” may not, in fact, be a “change”. With the website that I’m working with, a property might be totally absent, might be assigned a primitive (e.g., string, int, etc.), or might consist of a complex object. For example, for a property called “HomeInfo”, the property may be completely missing, might have “Not Applicable”, or might be a complex object consisting of Persons, Address, Phone, etc. As far as the API is concerned, any and all of these are “correct”, but it renders trying to deserialize according to an object model absolutely impossible — unless, of course, one has your marvelous code as a backup.
Some additional helpful hints, particular for pesky compiler error messages:
o “new JavaScriptSerializer()” can also be written “new System.Web.Script.Serialization.JavaScriptSerializer()” if your missing the appropriate “using” statement.
o Similarly, Ilist, IDictionary, etc. are under “System.Collections”, NOT the more prevalent “System.Collections.Generic”. You’ll know you have this issue when you see an error message like “Using the generic type ‘System.Collections.Generic.IList’ requires 1 type arguments”. To solve it, insert a “using System.Collections;” statement, or use explicit referencing, as in “System.Collections.IList arr = …”
o In order to use a ‘dynamic’ variable as set forth in the code, you must have “Microsoft.CSharp” included in your ‘References’. If it’s not, do the standard right-click on ‘References’, select “Add Reference”, and select it from the list. Note that is listed under “Microsoft”, NOT “System”.
o I could not get the “(dynamic)” cast in “val.Add((dynamic)DeserializeObject(obj as Dictionary, tipGen));” to work. I did get the statement to work using “val.Add(DeserializeObject(obj as Dictionary, tipGen) as dynamic);” — note the “as dynamic” at the end.
o Lastly (and this is a purely style comment), I had a bit of trouble understanding the code because I had trouble relating to the assigned names. So, the “DeserializeObject” method became “JSONDeserializationAlternative” in order to separate it from all the other possibilities that might be bouncing around within the .Net code. “dictItem” became “dictJSON”. “tip” became “classType”. “ptip” became “proptype”. Etc. Renaming variables obviously did nothing to the code itself — it merely served for me to better relate to the purpose of a given variable, and what was going on with it within the code. And, I understand that this purely personal. However, I pass the hint along in case others might find it useful … And, to repeat, to each his/her own!