json.net - how to add property $type ONLY on root object -


i want modify json.net serializer add $type property objects implements given interface not property or nested objects.

with typenamehandling.auto (default)

{   "propertya": 123,   "propertyb": "foo",   "propertyc": [1, 2, 3, 4] } 

with typenamehandling.all

{   "$type": "jsonnettypenamehandling.testevent, jsonnettypenamehandling",   "propertya": 123,   "propertyb": "foo",   "propertyc": {     "$type": "system.collections.generic.list`1[[system.int32, mscorlib]], mscorlib",     "$values": [1, 2, 3, 4 ]   } } 

what want

{   "$type": "jsonnettypenamehandling.testevent, jsonnettypenamehandling",   "propertya": 123,   "propertyb": "foo",   "propertyc": [1, 2, 3, 4] } 

i experimenting custom contractresolver don't work:

class program {     static void main(string[] args)     {         var serializersettings = new jsonserializersettings()         {             typenamehandling = typenamehandling.auto,             typenameassemblyformat = system.runtime.serialization.formatters.formatterassemblystyle.simple,             nullvaluehandling = newtonsoft.json.nullvaluehandling.ignore,             contractresolver = new enabletypenamehandlingallonlyforevents(),             formatting = formatting.indented         };          var event1 = new testevent() { propertya = 123, propertyb = "foo", propertyc = new list<int> { 1, 2, 3, 4 } };          string event1serialized = jsonconvert.serializeobject(event1, serializersettings);          console.writeline(event1serialized);         console.readline();     } }  public interface ievent { }  public class testevent : ievent {     public int propertya { get; set; }     public string propertyb { get; set; }     public list<int> propertyc { get; set; } }  public class enabletypenamehandlingallonlyforevents : defaultcontractresolver {     protected override jsonobjectcontract createobjectcontract(type objecttype)     {         var x = base.createobjectcontract(objecttype);          if (typeof(ievent).isassignablefrom(x.underlyingtype))         {             // tell json.net add $type instances of (ievent) type???         }          return x;     } } 

if require "$type" property on root object , ok appearing on nested polymorphic objects , arrays if required, use following overload along typenamehandling.auto: jsonconvert.serializeobject(object, type, jsonserializersettings).

from docs:

public static string serializeobject(     object value,     type type,     jsonserializersettings settings ) 

type type: system.type type of value being serialized. parameter used when typenamehandling auto write out type name if type of value not match. specifing type optional.

i.e., do:

var serializersettings = new jsonserializersettings() {     typenamehandling = typenamehandling.auto,     typenameassemblyformat = system.runtime.serialization.formatters.formatterassemblystyle.simple,     nullvaluehandling = newtonsoft.json.nullvaluehandling.ignore,     formatting = formatting.indented };  var event1serialized = jsonconvert.serializeobject(event1, typeof(ievent), serializersettings); 

if require "$type" on root object , not accept on nested polymorphic objects , arrays if otherwise required, need use typenamehandling.all along custom contract resolver sets jsoncontainercontract.itemtypenamehandling = typenamehandling.none:

public class suppressitemtypenamecontractresolver : defaultcontractresolver {     // of 7.0.1, json.net suggests using static instance "stateless" contract resolvers, performance reasons.     // http://www.newtonsoft.com/json/help/html/contractresolver.htm     // http://www.newtonsoft.com/json/help/html/m_newtonsoft_json_serialization_defaultcontractresolver__ctor_1.htm     // "use parameterless constructor , cache instances of contract resolver within application optimal performance."     static suppressitemtypenamecontractresolver instance;      // using static constructor enables lazy initialization.  http://csharpindepth.com/articles/general/singleton.aspx     static suppressitemtypenamecontractresolver() { instance = new suppressitemtypenamecontractresolver(); }      public static suppressitemtypenamecontractresolver instance { { return instance; } }      protected suppressitemtypenamecontractresolver() : base() { }      protected override jsoncontract createcontract(type objecttype)     {         var contract = base.createcontract(objecttype);         var containercontract = contract jsoncontainercontract;         if (containercontract != null)         {             if (containercontract.itemtypenamehandling == null)                 containercontract.itemtypenamehandling = typenamehandling.none;          }         return contract;     } } 

then use like:

var serializersettings = new jsonserializersettings() {     typenamehandling = typenamehandling.all,     contractresolver = suppressitemtypenamecontractresolver.instance,     typenameassemblyformat = system.runtime.serialization.formatters.formatterassemblystyle.simple,     nullvaluehandling = newtonsoft.json.nullvaluehandling.ignore,     formatting = formatting.indented };  var event1serialized = jsonconvert.serializeobject(event1, serializersettings); 

finally, take note of caution newtonsoft docs:

typenamehandling should used caution when application deserializes json external source. incoming types should validated custom serializationbinder when deserializing value other none.

for discussion of why may necessary, see typenamehandling caution in newtonsoft json, how configure json.net create vulnerable web api, , alvaro muñoz & oleksandr mirosh's blackhat paper https://www.blackhat.com/docs/us-17/thursday/us-17-munoz-friday-the-13th-json-attacks-wp.pdf


Comments

Popular posts from this blog

matlab - error with cyclic autocorrelation function -

django - (fields.E300) Field defines a relation with model 'AbstractEmailUser' which is either not installed, or is abstract -

c# - What is a good .Net RefEdit control to use with ExcelDna? -