ASP.Net MVC3 JSON.Net Custom ValueProviderFactory

Mar 2, 2012 at 9:01 PM


I just finished up this bit of code that I wanted to share :). Basically, you can swap out the MVC3 JsonValueProviderFactory cleanly with my JsonNetValueProviderFactory. It even supports collections!

In your MVC3 Application_Start() (removal of the MS Json (de)serializer):


        protected void Application_Start()
            // setup ASP.Net MVC
            // setup value providers
            ValueProviderFactories.Factories.Add(new JsonNetValueProviderFactory());

JsonNetValueProviderFactory.cs (Client -> MVC3 Deserialization):


    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)
            StreamReader streamReader = new StreamReader(controllerContext.HttpContext.Request.InputStream);
            // convert stream reader to a JSON Text Reader
            JsonTextReader JSONReader = new JsonTextReader(streamReader);
            // tell JSON to read
            if (!JSONReader.Read())
                return null;

            // make a new Json serializer
            JsonSerializer 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);
                JSONObject = JSONSerializer.Deserialize<ExpandoObject>(JSONReader);

            // create a backing store to hold all properties for this deserialization
            Dictionary<string, object> 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)
            IDictionary<string, object> d = value as IDictionary<string, object>;
            if (d != null)
                foreach (KeyValuePair<string, object> entry in d)
                    AddToBackingStore(backingStore, MakePropertyKey(prefix, entry.Key), entry.Value);

            IList l = value as IList;
            if (l != null)
                for (int i = 0; i < l.Count; i++)
                    AddToBackingStore(backingStore, MakeArrayKey(prefix, i), l[i]);

            // 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;

JsonNetResult.cs (MVC3 -> Client Seserialization):


    public class JsonNetResult : JsonResult
        public JsonSerializerSettings SerializerSettings { get; set; }

        public JsonNetResult() : base()
            // create serializer settings
            this.SerializerSettings = new JsonSerializerSettings();
            // setup default serializer settings
            this.SerializerSettings.Converters.Add(new IsoDateTimeConverter());

        public override void ExecuteResult(ControllerContext context)
            // verify we have a contrex
            if (context == null)
                throw new ArgumentNullException("context");

            // get the current http context response
            var response = context.HttpContext.Response;
            // set content type of response
            response.ContentType = !String.IsNullOrEmpty(ContentType) ? ContentType : "application/json";
            // set content encoding of response
            if (ContentEncoding != null)
                response.ContentEncoding = this.ContentEncoding;

            // verify this response has data
            if (this.Data == null)

            // serialize the object to JSON using JSON.Net
            String JSONText = JsonConvert.SerializeObject(this.Data, Formatting.Indented, this.SerializerSettings);
            // write the response

ControllerExtensions.cs (Allows simple access to JsonNetResult from within a MVC3 Controller):


    public static class ControllerExtensions
        public static JsonNetResult JsonNet(this Controller controller, object data)
            return new JsonNetResult() { Data = data };

Example (from within a MVC3 Controller):


    public class StartController : Controller
        public ActionResult Index()
            // setup start
            Start start = new Start();
            // return view
            return View(start);

        public ActionResult Test(Mob[] m)
            return this.JsonNet(m);


Alex (


May 15, 2012 at 6:14 AM

Works like a charm! Thank you very much!

May 28, 2012 at 1:40 AM

Unfortunately, this implementation of JsonNetValueProviderFactory does not support dictionaries.

May 28, 2012 at 7:40 PM
Edited May 28, 2012 at 7:42 PM

How are you trying to represent the dictionary in JSON?

{ 'key1': 'value1', 'key2': 'value2' }

And is this to or from MVC3?

You will likely have to play with:

// 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>(JSONReader);
                JSONObject = JSONSerializer.Deserialize(JSONReader);

To get it to work :)

May 28, 2012 at 7:44 PM

Something along the lines of:

JSONObject = JSONSerializer.Deserialize<Dictionary<String, ExpandoObject>>(JSONReader);
Would be my guess.

May 29, 2012 at 8:58 AM

Actually my point is that there is no easy way to distinguish object and dictionary in JsonNetValueProviderFactory to return proper values in IValueProvider.

In this case only custom model binder or meta-property in json are available as options.

Jun 12, 2012 at 11:44 AM

This was helpful

Jul 3, 2013 at 6:59 PM
I am having trouble deserializing a custom object. I have created a CustomConverter class and added it to the property like so:
        Public Property Item As TestItem
                Return _item
            End Get
            Set(ByVal value As TestItem)
                item = value
            End Set
        End Property
When I step through the code in the JsonNetValueProviderFactory class, it does not reach my custom converter class. I am able to serialize it using the custom converter manually, but when it doesn't work in the GetValueProvider function.
Sep 26, 2013 at 10:17 AM
Edited Sep 26, 2013 at 10:18 AM
This lines may be a problem
if (this.Data == null)
So a empty response is generated instead of "null", what jQuery consider a fail.
Apr 15, 2014 at 8:52 PM
Doesn't seem to handle dates or nested dictionaries
Aug 15, 2014 at 7:31 PM
This has some issues with enums and the exact value not serializing if its a null enum property.
Aug 24, 2014 at 8:43 PM
One more thing - line with

// make a new Json serializer
JsonSerializer JSONSerializer = new JsonSerializer();

should look like (in 2014-08-24 ;) )
// make a new Json serializer
var jsonSerializer = JsonSerializer.CreateDefault();

so construction in Global.asax for example

protected void Application_Start()

        ValueProviderFactories.Factories.Add(new JsonNetValueProviderFactory());
        JsonConvert.DefaultSettings = () => new JsonSerializerSettings
            TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple,
            TypeNameHandling = TypeNameHandling.All

will work ;)
Apr 30, 2015 at 9:19 AM
Edited Apr 30, 2015 at 10:02 AM

I found that it read my dateTime incorrectly.
JSON.stringify({ "ShopId": shopId, "StartDate": startDate, "EndDate": endDate })
My startDate is in GMT format like this:
Mon Apr 27 2015 00:00:00 GMT+0800 (China Standard Time)

but seem the streamreader converted it to ISO format, so I get

How to solve this problem?

Thank you


My work around:
At AddToBackingStore:
 foreach (KeyValuePair<string, object> entry in d)
                    var entryValue = entry.Value;
                    if (entryValue.GetType().Name == "DateTime") //Convert Utc to GMT +8
                        entryValue = ((DateTime)entryValue).AddHours(8);
                    AddToBackingStore(backingStore, MakePropertyKey(prefix, entry.Key), entryValue);
Any better solution?
May 12, 2015 at 4:20 AM
How to handle Enum?
It can not change the Int to enum.
Mar 5 at 5:54 AM
There're a lot of resources on how to substitute the Json.NET library as the default serializer in ASP.NET MVC apps, but, for the life of me, I can't find a single resource on how to set it as the default deserializer.

To illustrate that a bit, here's some template code:
                         //     //    //    // how to use Json.NET when deserializing
                        //    //    //      // incoming arguments?
public ActionResult SomeAction ( Foo foo ) {
//    //    //      //  this piece of code has lots of resources
// // // // on how to override the default Javascript serializer
return Json(new Bar());

How do I tell my application to use Json.NET when deserializing incoming parameters in controller actions, say, from a jQuery AJAX call?

type : 'POST',
data : { foo : 'bar' }

I've tried adapting MediaTypeFormatters into my code by adjusting this resource , but that didn't work either. Note that I'm not in a WebAPI environment --- but I expect that one solution that works on a normal Controller should work (albeit with minimal adjustments) in an ApiController.

May 27 at 4:20 PM
Edited May 27 at 4:20 PM
This doesn't seem to work when parsing this :
May 29 at 7:45 PM
Edited May 29 at 7:46 PM

I revisited this page to put some comment - in fact from long time I do not use normal MVC controllers to pass data to/from frontend - too cumbersome to set it properly.
I moved to web api controllers (and OWIN) which are much easier to work with - setting this as
httpConfiguration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
solved all my previous headaches with having camel case on frontend side. Combining that with T4TS and I am set (as I use typescript on frontend side)

Best regards