It has been decided by the ASP.NET Web API team to use the JSON.NET library for model binding JSON data. However, "normal" MVC controllers still use the inferior JsonDataContractSerializer. This causes issues with parsing dates, and is causing me much headache.
See this for reference:
http://www.devcurry.com/2013/04/json-dates-are-different-in-aspnet-mvc.html
The author chooses to solve the issue in the Knockout layer on the client. But I would prefer to solve this by using the same JSON.NET model binder in MVC controllers as in Web API controllers.
How do I substitute a different JSON model binder into ASP.NET MVC? Specifically, the JSON.NET library. Using the same model binder from Web API would be ideal if possible.
Model binding is a well-designed bridge between the HTTP request and the C# action methods. It makes it easy for developers to work with data on forms (views), because POST and GET is automatically transferred into a data model you specify. ASP.NET MVC uses default binders to complete this behind the scene.
asp.net mvc supports data binding. You can bind data to some model and post it back when the form is submitted.
I have done this, and also heavily customized the serialization that Json.NET is doing, by:
Replace the default formatter in global.asax.cs, Application_Start
:
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.JsonFormatter);
GlobalConfiguration.Configuration.Formatters.Add(new CustomJsonMediaTypeFormatter());
And my CustomJsonMediaTypeFormatter is:
public static class CustomJsonSettings
{
private static JsonSerializerSettings _settings;
public static JsonSerializerSettings Instance
{
get
{
if (_settings == null)
{
var settings = new JsonSerializerSettings();
// Must convert times coming from the client (always in UTC) to local - need both these parts:
settings.Converters.Add(new IsoDateTimeConverter { DateTimeStyles = System.Globalization.DateTimeStyles.AssumeUniversal }); // Critical part 1
settings.DateTimeZoneHandling = DateTimeZoneHandling.Local; // Critical part 2
// Skip circular references
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
// Handle special cases in json (self-referencing loops, etc)
settings.ContractResolver = new CustomJsonResolver();
_settings = settings;
}
return _settings;
}
}
}
public class CustomJsonMediaTypeFormatter : MediaTypeFormatter
{
public JsonSerializerSettings _jsonSerializerSettings;
public CustomJsonMediaTypeFormatter()
{
_jsonSerializerSettings = CustomJsonSettings.Instance;
// Fill out the mediatype and encoding we support
SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
SupportedEncodings.Add(new UTF8Encoding(false, true));
}
public override bool CanReadType(Type type)
{
return true;
}
public override bool CanWriteType(Type type)
{
return true;
}
public override Task<object> ReadFromStreamAsync(Type type, Stream stream, HttpContent content, IFormatterLogger formatterLogger)
{
// Create a serializer
JsonSerializer serializer = JsonSerializer.Create(_jsonSerializerSettings);
// Create task reading the content
return Task.Factory.StartNew(() =>
{
using (StreamReader streamReader = new StreamReader(stream, SupportedEncodings.First()))
{
using (JsonTextReader jsonTextReader = new JsonTextReader(streamReader))
{
return serializer.Deserialize(jsonTextReader, type);
}
}
});
}
public override Task WriteToStreamAsync(Type type, object value, Stream stream, HttpContent content, TransportContext transportContext)
{
// Create a serializer
JsonSerializer serializer = JsonSerializer.Create(_jsonSerializerSettings);
// Create task writing the serialized content
return Task.Factory.StartNew(() =>
{
using (StreamWriter streamWriter = new StreamWriter(stream, SupportedEncodings.First()))
{
using (JsonTextWriter jsonTextWriter = new JsonTextWriter(streamWriter))
{
serializer.Serialize(jsonTextWriter, value);
}
}
});
}
}
And finally, the CustomJsonResolver:
public class CustomJsonResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, Newtonsoft.Json.MemberSerialization memberSerialization)
{
var list = base.CreateProperties(type, memberSerialization);
// Custom stuff for my app
if (type == typeof(Foo))
{
RemoveProperty(list, "Bar");
RemoveProperty(list, "Bar2");
}
return list;
}
private void RemoveProperty(IList<JsonProperty> list, string propertyName)
{
var rmc = list.FirstOrDefault(x => x.PropertyName == propertyName);
if (rmc != null)
{
list.Remove(rmc);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With