Share via


How to increase maxJsonLength for JSON POST in MVC3

Question

Monday, December 19, 2011 10:54 AM

I have an MVC 3 web site that i am building that needs to be able to handle a large amount of JSON data submitted to a controller's action via HTTP POST.  I currently get the following error in the event log:

Exception information:

    Exception type: ArgumentException

    Exception message: Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property.

I have this in my web.config:

  <system.web.extensions>
    <scripting>
      <webServices>
        <jsonSerialization maxJsonLength="2147483647"/>
      </webServices>
    </scripting>
  </system.web.extensions>

I have seen several articles on implementing a custom JsonResult object.  However, I am recieving JSON data, not returning JSON data (weill, I am actually, just not large amounts)
How can I increase this limit for recieving a JSON POST?
Thanks.

 

All replies (3)

Monday, December 19, 2011 11:11 AM ✅Answered

the MVC json serializer does not look at the webconfig to get the max length (thats for asp.net web services). you need to use your own serializer. you override ExecuteResult and supply you own json serializer. to override the input, create a new JsonValueProviderFactory, then override ValueProvider in the controller to return your new json factory when its a json request.

 


Monday, December 19, 2011 11:55 AM ✅Answered

Ok, thank you, Bruce for the explanation.  I got this working.  I figured I would share the solution for anyone else running into this.

First you must build a custom JsonValueProviderFactory.  To do this I downloaded the MVC 3 source code and found the JsonValueProviderFactory.cs.  Using this class as a template I created a CustomJsonValueProviderFactory.  Here is the source.  I only added one line of code to GetDeserializedObject.  It is commented.

 

public sealed class CustomJsonValueProviderFactory : ValueProviderFactory
    {

        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);
                }
                return;
            }

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

            // primitive
            backingStore[prefix] = value;
        }

        private static object GetDeserializedObject(ControllerContext controllerContext)
        {
            if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
            {
                // not JSON request
                return null;
            }

            StreamReader reader = new StreamReader(controllerContext.HttpContext.Request.InputStream);
            string bodyText = reader.ReadToEnd();
            if (String.IsNullOrEmpty(bodyText))
            {
                // no JSON data
                return null;
            }

            JavaScriptSerializer serializer = new JavaScriptSerializer();
            serializer.MaxJsonLength = int.MaxValue; //increase MaxJsonLength.  This could be read in from the web.config if you prefer
            object jsonData = serializer.DeserializeObject(bodyText);
            return jsonData;
        }

        public override IValueProvider GetValueProvider(ControllerContext controllerContext)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }

            object jsonData = GetDeserializedObject(controllerContext);
            if (jsonData == null)
            {
                return null;
            }

            Dictionary<string, object> backingStore = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
            AddToBackingStore(backingStore, String.Empty, jsonData);
            return new DictionaryValueProvider<object>(backingStore, CultureInfo.CurrentCulture);
        }

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

 

With that in place I modified the Global.asax.cs Application_Start method as such:

protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);

            //find the default JsonVAlueProviderFactory
            JsonValueProviderFactory jsonValueProviderFactory = null;

            foreach (var factory in ValueProviderFactories.Factories)
            {
                if (factory is JsonValueProviderFactory)
                {
                    jsonValueProviderFactory = factory as JsonValueProviderFactory;
                }
            }

            //remove the default JsonVAlueProviderFactory
            if (jsonValueProviderFactory != null) ValueProviderFactories.Factories.Remove(jsonValueProviderFactory);

            //add the custom one
            ValueProviderFactories.Factories.Add(new CustomJsonValueProviderFactory());

        }

That's all it took.  Such a simple fix seems like it should have been handled in the base framework. 

Hope this helps someone down the road.

 

 


Thursday, July 19, 2012 5:21 PM

I had the same exact problem in MVC3 and .NET 4.0. I was excited to find this post, but it didn't work. I implemented the custom class and put the stuff in global.asax.cs. No dice -- same error.

Any other ideas on this?