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!
4 Responses