c# - Can I serialize nested properties to my class in one operation with Json.net? -


lets have model like:

public class mymodel {     public string name { get; set; }     public string[] size { get; set; }     public string weight { get; set; }  } 

and json this:

{     "name" : "widget",     "details" : {         "size" : [             "xl","m","s",         ]         "weight" : "heavy"     } } 

i have been trying work out way serialize object without making 1 model "name" , 1 model "details" doesn't map nicely database involves little juggling class populated.

i can make multiple passes @ jsonconvert.populateobject() like:

var mod = new mymodel();  jsonconvert.populateobject(json.tostring(), mod); jsonconvert.populateobject(json["details"].tostring(), mod); 

but in real code running multiple threads , populateobject not thread safe, jams app. comments populatejsonasync() not use instead use task.run() on populateobject().

this not work , still locks app when call like:

await task.run(() => jsonconvert.populateobject(response.tostring(), productdetail));  if (response["results"].hasvalues) {     await task.run(() => jsonconvert.populateobject(response["results"][0].tostring(), productdetail)); } 

a few through app gets thread locked. if remove populateobject threads terminate fine pretty sure function not thread safe.

is there neat threadsafe approach populating object in single step?

you can following converter:

public class mymodelconverter : jsonconverter {     [threadstatic]     static bool cannotwrite;      // disables converter in thread-safe manner.     bool cannotwrite { { return cannotwrite; } set { cannotwrite = value; } }      public override bool canwrite { { return !cannotwrite; } }      public override bool canconvert(type objecttype)     {         return typeof(mymodel).isassignablefrom(objecttype);     }      public override object readjson(jsonreader reader, type objecttype, object existingvalue, jsonserializer serializer)     {         var obj = jobject.load(reader);         obj.selecttoken("details.size").moveto(obj);         obj.selecttoken("details.weight").moveto(obj);         using (reader = obj.createreader())         {             // using "populate" avoids infinite recursion.             existingvalue = (existingvalue ?? new mymodel());             serializer.populate(reader, existingvalue);         }         return existingvalue;     }      public override void writejson(jsonwriter writer, object value, jsonserializer serializer)     {         // disabling writing prevents infinite recursion.         using (new pushvalue<bool>(true, () => cannotwrite, val => cannotwrite = val))         {             var obj = jobject.fromobject(value, serializer);             var details = new jobject();             obj.add("details", details);              obj["size"].moveto(details);             obj["weight"].moveto(details);             obj.writeto(writer);         }     } }  public static class jsonextensions {     public static void moveto(this jtoken token, jobject newparent)     {         if (newparent == null)             throw new argumentnullexception();         if (token != null)         {             if (token jproperty)             {                 token.remove();                 newparent.add(token);             }             else if (token.parent jproperty)             {                 token.parent.remove();                 newparent.add(token.parent);             }             else             {                 throw new invalidoperationexception();             }         }     } }  public struct pushvalue<t> : idisposable {     action<t> setvalue;     t oldvalue;      public pushvalue(t value, func<t> getvalue, action<t> setvalue)     {         if (getvalue == null || setvalue == null)             throw new argumentnullexception();         this.setvalue = setvalue;         this.oldvalue = getvalue();         setvalue(value);     }      #region idisposable members      // using disposable struct avoid overhead of allocating , freeing instance of finalizable class.     public void dispose()     {         if (setvalue != null)             setvalue(oldvalue);     }      #endregion } 

and use this:

[jsonconverter(typeof(mymodelconverter))] public class mymodel {     [jsonproperty("name")]     public string name { get; set; }     [jsonproperty("size")]     public string[] size { get; set; }     [jsonproperty("weight")]     public string weight { get; set; } }  public class testclass {     public static void test()     {         string json = @"{             ""name"" : ""widget"",             ""details"" : {                 ""size"" : [                     ""xl"",""m"",""s"",                 ],                 ""weight"" : ""heavy""             }         }";         var mod = jsonconvert.deserializeobject<mymodel>(json);         debug.writeline(jsonconvert.serializeobject(mod, formatting.indented));     } } 

the readjson() method straightforward: deserialize jobject, restructure appropriate properties, populate mymodel class. writejson little more awkward; converter needs temporarily disable in thread-safe manner generate "default" jobject can restructured.


Comments

Popular posts from this blog

android - MPAndroidChart - How to add Annotations or images to the chart -

javascript - Add class to another page attribute using URL id - Jquery -

firefox - Where is 'webgl.osmesalib' parameter? -