Is there a good example on how to create a MediaTypeFormatter/JsonConverter that can handle serialization/deserialization of json to dynamic?
I have the following scenario.
A class User that is abstract, from the User class I create an Administrator class that inherits and extends the User class.
Now I want to use the web api / api controller to save any object that extends/inherits the User class and as far as I know a custom mediatypeformatter can help me with this? Is there any example or maybe someone else have already done this?
This is some sample code to visual explain what I'm trying to do http://pastebin.com/sRGW62yw
However it sounds to me like you'd be better off using inheritance, i.e. get an object of runtime type Administrator for your User-typed parameter. I thought that would simply be a matter of specifying the "__type" field in the JSON, but that doesn't seem
to be working for me. I'll let you know if I figure out anything more.
Is your scenario sth like this? If yes, then you could easily enable this by opting in to go with de-serialization path instead of model binding the body data. Client could sent Administrator and it could be read in to User object as Administrator. It could
be easily acheived with a read policy below.
public class ReadAsSingleObjectPolicy : IRequestContentReadPolicy
{
public RequestContentReadKind GetRequestContentReadKind(HttpActionDescriptor actionDescriptor)
{
//Serialization approach for specific action
if (actionDescriptor.ActionName.Equals("ACTIONNAME"))
{
return RequestContentReadKind.AsSingleObject;
}
else //Default
{
return RequestContentReadKind.AsKeyValuePairs;
}
}
}
Configuring it
config.ServiceResolver.SetService(typeof(IRequestContentReadPolicy), new ReadAsSingleObjectPolicy());
I find that whenever the AsSingleObject kind is specified the route parameters don't get filled in. In this case the id would be null. Do you know any way around that?
It should have worked with RouteData because it has nothing to do with how we are reading the body. How about as part of a querystring instead of route data?
How about as part of a querystring instead of route data?
Nope, query string parameters don't seem to get filled in while in this mode either. Something interesting I found is that the route data is actually present in the ControllerContext.RouteData, but it just doesn't get filled in to the method parameters.
However it sounds to me like you'd be better off using inheritance, i.e. get an object of runtime type Administrator for your User-typed parameter. I thought that would simply be a matter of specifying the "__type" field in the JSON, but that doesn't seem
to be working for me. I'll let you know if I figure out anything more.
I cannot use JsonValue when I do put, I get a server error when I try to use it. Any ideas?
kloojed
Member
9 Points
6 Posts
Write a MediaTypeFormatter that can serialize/deserialize json to dynamic
Feb 28, 2012 01:50 PM|LINK
Is there a good example on how to create a MediaTypeFormatter/JsonConverter that can handle serialization/deserialization of json to dynamic?
I have the following scenario.
A class User that is abstract, from the User class I create an Administrator class that inherits and extends the User class.
Now I want to use the web api / api controller to save any object that extends/inherits the User class and as far as I know a custom mediatypeformatter can help me with this? Is there any example or maybe someone else have already done this?
This is some sample code to visual explain what I'm trying to do http://pastebin.com/sRGW62yw
dcstraw
Member
37 Points
21 Posts
Re: Write a MediaTypeFormatter that can serialize/deserialize json to dynamic
Feb 28, 2012 06:14 PM|LINK
You can get a dynamic from JSON by accepting a JsonValue parameter:
public void Put(string id, JsonValue content) { dynamic dynamicContent = content.AsDynamic(); }However it sounds to me like you'd be better off using inheritance, i.e. get an object of runtime type Administrator for your User-typed parameter. I thought that would simply be a matter of specifying the "__type" field in the JSON, but that doesn't seem to be working for me. I'll let you know if I figure out anything more.
dravva
Member
142 Points
31 Posts
Microsoft
Re: Write a MediaTypeFormatter that can serialize/deserialize json to dynamic
Feb 28, 2012 06:25 PM|LINK
class User { .. }
class Administrator : User { .. }
Is your scenario sth like this? If yes, then you could easily enable this by opting in to go with de-serialization path instead of model binding the body data. Client could sent Administrator and it could be read in to User object as Administrator. It could be easily acheived with a read policy below.
public class ReadAsSingleObjectPolicy : IRequestContentReadPolicy { public RequestContentReadKind GetRequestContentReadKind(HttpActionDescriptor actionDescriptor) { //Serialization approach for specific action if (actionDescriptor.ActionName.Equals("ACTIONNAME")) { return RequestContentReadKind.AsSingleObject; } else //Default { return RequestContentReadKind.AsKeyValuePairs; } } } Configuring it config.ServiceResolver.SetService(typeof(IRequestContentReadPolicy), new ReadAsSingleObjectPolicy());dcstraw
Member
37 Points
21 Posts
Re: Write a MediaTypeFormatter that can serialize/deserialize json to dynamic
Feb 28, 2012 06:39 PM|LINK
dravva,
I find that whenever the AsSingleObject kind is specified the route parameters don't get filled in. In this case the id would be null. Do you know any way around that?
dcstraw
Member
37 Points
21 Posts
Re: Write a MediaTypeFormatter that can serialize/deserialize json to dynamic
Feb 28, 2012 06:42 PM|LINK
Also note that you'll need to specify this attribute on your User class in order for the serializer to recognize the Administrator class:
dravva
Member
142 Points
31 Posts
Microsoft
Re: Write a MediaTypeFormatter that can serialize/deserialize json to dynamic
Feb 28, 2012 06:45 PM|LINK
It should have worked with RouteData because it has nothing to do with how we are reading the body. How about as part of a querystring instead of route data?
dcstraw
Member
37 Points
21 Posts
Re: Write a MediaTypeFormatter that can serialize/deserialize json to dynamic
Feb 28, 2012 06:50 PM|LINK
Nope, query string parameters don't seem to get filled in while in this mode either. Something interesting I found is that the route data is actually present in the ControllerContext.RouteData, but it just doesn't get filled in to the method parameters.
kloojed
Member
9 Points
6 Posts
Re: Write a MediaTypeFormatter that can serialize/deserialize json to dynamic
Feb 28, 2012 08:45 PM|LINK
I cannot use JsonValue when I do put, I get a server error when I try to use it. Any ideas?
dcstraw
Member
37 Points
21 Posts
Re: Write a MediaTypeFormatter that can serialize/deserialize json to dynamic
Feb 28, 2012 09:05 PM|LINK
What error do you get?
kloojed
Member
9 Points
6 Posts
Re: Write a MediaTypeFormatter that can serialize/deserialize json to dynamic
Feb 28, 2012 09:16 PM|LINK
This is the data I send to the controller http://cl.ly/Ec5j and the error is a 500 server error like this http://cl.ly/Ebp1
I use a custom JsonNetFormatter to get camel case property names, this is the code I use
public class JsonNetFormatter : MediaTypeFormatter { private readonly JsonSerializerSettings _settings; public JsonNetFormatter(JsonSerializerSettings settings = null) { this._settings = settings ?? new JsonSerializerSettings(); SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json")); Encoding = new UTF8Encoding(false, true); } protected override bool CanReadType(Type type) { return type != typeof(IKeyValueModel); } protected override bool CanWriteType(Type type) { return true; } protected override Task<object> OnReadFromStreamAsync(Type type, Stream stream, HttpContentHeaders contentHeaders, FormatterContext formatterContext) { var ser = JsonSerializer.Create(_settings); return Task.Factory.StartNew(() => { using (var strdr = new StreamReader(stream)) using (var jtr = new JsonTextReader(strdr)) { var deserialized = ser.Deserialize(jtr, type); return deserialized; } }); } protected override Task OnWriteToStreamAsync(Type type, object value, Stream stream, HttpContentHeaders contentHeaders, FormatterContext formatterContext, TransportContext transportContext) { JsonSerializer ser = JsonSerializer.Create(_settings); return Task.Factory.StartNew(() => { using (JsonTextWriter w = new JsonTextWriter(new StreamWriter(stream, Encoding)) { CloseOutput = false}) { ser.Serialize(w, value); w.Flush(); } }); } }And this is how I use it
var config = GlobalConfiguration.Configuration; config.Formatters[0] = new JsonNetFormatter(new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver(), Converters = { new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd hh:mm:ss" } } });