Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Json.NET for JSON modelbinding in an MVC5 project?

I've been looking around the internet for an answer or example, but could not find one yet. I simply would like to change the default JSON serializer which is used to deserialize JSON while modelbinding to JSON.NET library.

I've found this SO post, but cannot implement it so far, I can't even see the System.Net.Http.Formatters namespace, nor can I see GlobalConfiguration.

What am I missing?

UPDATE

I have an ASP.NET MVC project, it was basically an MVC3 project. Currently I'm targetting .NET 4.5 and using the ASP.NET MVC 5 and related NuGet packages.

I don't see the System.Web.Http assembly, nor any similar namespace. In this context I would like to inject JSON.NET to be used as the default model binder for JSON type of requests.

like image 262
Zoltán Tamási Avatar asked Jun 02 '14 13:06

Zoltán Tamási


1 Answers

I've finally found an answer. Basically I don't need the MediaTypeFormatter stuff, that's not designed to be used in MVC environment, but in ASP.NET Web APIs, that's why I do not see those references and namespaces (by the way, those are included in the Microsoft.AspNet.WeApi NuGet package).

The solution is to use a custom value provider factory. Here is the code required.

    public class JsonNetValueProviderFactory : ValueProviderFactory     {         public override IValueProvider GetValueProvider(ControllerContext controllerContext)         {             // first make sure we have a valid context             if (controllerContext == null)                 throw new ArgumentNullException("controllerContext");              // now make sure we are dealing with a json request             if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))                 return null;              // get a generic stream reader (get reader for the http stream)             var streamReader = new StreamReader(controllerContext.HttpContext.Request.InputStream);             // convert stream reader to a JSON Text Reader             var JSONReader = new JsonTextReader(streamReader);             // tell JSON to read             if (!JSONReader.Read())                 return null;              // make a new Json serializer             var JSONSerializer = new JsonSerializer();             // add the dyamic object converter to our serializer             JSONSerializer.Converters.Add(new ExpandoObjectConverter());              // use JSON.NET to deserialize object to a dynamic (expando) object             Object JSONObject;             // if we start with a "[", treat this as an array             if (JSONReader.TokenType == JsonToken.StartArray)                 JSONObject = JSONSerializer.Deserialize<List<ExpandoObject>>(JSONReader);             else                 JSONObject = JSONSerializer.Deserialize<ExpandoObject>(JSONReader);              // create a backing store to hold all properties for this deserialization             var backingStore = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);             // add all properties to this backing store             AddToBackingStore(backingStore, String.Empty, JSONObject);             // return the object in a dictionary value provider so the MVC understands it             return new DictionaryValueProvider<object>(backingStore, CultureInfo.CurrentCulture);         }          private static void AddToBackingStore(Dictionary<string, object> backingStore, string prefix, object value)         {             var d = value as IDictionary<string, object>;             if (d != null)             {                 foreach (var entry in d)                 {                     AddToBackingStore(backingStore, MakePropertyKey(prefix, entry.Key), entry.Value);                 }                 return;             }              var l = value as IList;             if (l != null)             {                 for (var i = 0; i < l.Count; i++)                 {                     AddToBackingStore(backingStore, MakeArrayKey(prefix, i), l[i]);                 }                 return;             }              // primitive             backingStore[prefix] = value;         }          private static string MakeArrayKey(string prefix, int index)         {             return prefix + "[" + index.ToString(CultureInfo.InvariantCulture) + "]";         }          private static string MakePropertyKey(string prefix, string propertyName)         {             return (String.IsNullOrEmpty(prefix)) ? propertyName : prefix + "." + propertyName;         }     } 

And you can use it like this in your Application_Start method:

// remove default implementation     ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().FirstOrDefault()); // add our custom one ValueProviderFactories.Factories.Add(new JsonNetValueProviderFactory()); 

Here is the post which pointed me to the right direction, and also this one gave a good explanation on value providers and modelbinders.

like image 107
Zoltán Tamási Avatar answered Oct 15 '22 18:10

Zoltán Tamási