c# - Is it possible to set custom (de)serializers for open generic types in ServiceStack.Text? -


i have type this:

class foo<t> {   public string text { get; set; }    public t nested { get; set; }    public static string tojson(foo<t> foo) { [...] } } 

tojson serializes foo<bar> instance json in way impossible achieve tweaking jsconfig. also, tojson relies on servicestack.text serialize nested, can instance of foo<baz>.

unfortunately, way jsconfig implemented implies there jsconfig<t> set of static variables foo<bar> , other foo<baz>. also, afaik, servicestack.text offers no way configure json serialization open generic types (i.e.: jsconfig.add(typeof(foo<>), config)). tried solve issue creating static constructor foo<t>:

static foo() {   jsconfig<foo<t>>.rawserializefn = tojson; } 

this doesn't work time. depends on order static constructors invoked runtime. apparently, servicestack.text caches serializers functions , doing before static constructor called depending on order operations invoked in api, so:

var outer = new foo<baz> { text = "text" }; outer.tojson(); // ok, because nested null  var inner = new foo<bar>(); inner.tojson(); // ok, because jsconfig<foo<bar>>.rawserializefn foo<t>.tojson  outer.nested = inner; outer.tojson(); // not ok, because ss.text uses default serializer foo<t>, not foo<t>.tojson 

i can't set serializers in jsconfig<foo<t>> beforehand because t can virtually type, other generic types.

is possible define custom serialization routines open generic types (that can nested) in servicestack.text?

i solved in own way wrapper , custom deserializer. created base type of abstract types. base type tells system type is:

public class setsettingitembase {     public string key { get; set; }     public string valuetype { get; set; } } 

so base metadata -- setting key + value type. object dto, then, extends adding actual value:

public class setsettingitem : setsettingitembase {     public object value { get; set; } } 

note it's object. dto, not actual object. can cast later, or convert real/generic type after serialization.

my custom serialization is:

jsconfig<setsettingitem>.rawdeserializefn = str =>             {                 var basesettings = str.fromjson<setsettingitembase>();                 var ret = basesettings.mapto<setsettingitem>();                  if(true) // actual condition removed here... unimportant example                 {                     var datatype = constants.knownsettingstypes[basesettings.valuetype];                      var method = typeof(jsonextensions).getmethod("jsonto").makegenericmethod(datatype);                      var key = "value";                     var parsed = jsonobject.parse(str);                      if(parsed.object(key) == null)                         key = "value";                      ret.value = method.invoke(null, new object[] { parsed, key });                 }                 return ret;             }; 

this method first deserializes simple base. value passed in dto ignored when deserializing basesettings. call mapto prepare actual setsettingitem dto. mapto wrapper around automapper. use ss's built in mapper here.

for security, have set list of types allow settings. example:

knownsettingstypes.add("string", typeof(string)); knownsettingstypes.add("int", typeof(int)); knownsettingstypes.add("nullableint", typeof(int?)); knownsettingstypes.add("nullablepercentage", typeof(double?)); knownsettingstypes.add("feegrid", typeof(feegrid)); 

after that, use reflection jsonto method, passing in generic type parameter dynamically knownsettingstypes dictionary.

and finishing up, parse object using generic jsonobject.parse method , looking value or value (depending on case sensitivity) , explicitly convert jsonobject using dynamic method created earlier.

the end result can pass in settings of different types here part of dtos.

this served purposes time being, looking @ example see improving in 2 ways:

  1. after parsing, convert setsettingitem settingitem<t> use strongly-typed object in code. remember, example dtos across wire.
  2. instead of requiring person pass in type me check against, check against setting key know type supposed , parse accordingly. in example, if check against master list of settings , types, i'd still require them pass in type precaution , throw exception if didn't match.

Comments

Popular posts from this blog

how to proxy from https to http with lighttpd -

android - Automated my builds -

python - Flask migration error -