[asp.net-mvc] MaxJsonLength exception in ASP.NET MVC during JavaScriptSerializer

In one of my controller actions I am returning a very large JsonResult to fill a grid.

I am getting the following InvalidOperationException exception:

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

Setting the maxJsonLength property in the web.config to a higher value unfortunately does not show any effect.

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

I don't want to pass it back as a string as mentioned in this SO answer.

In my research I came across this blog post where writing an own ActionResult (e.g. LargeJsonResult : JsonResult) is recommended to bypass this behaviour.

Is this then the only solution?
Is this a bug in ASP.NET MVC?
Am I missing something?

Any help would be most appreciated.

This question is related to asp.net-mvc exception serialization jsonresult

The answer is


there is a bit other case - data is sent from client to server. when you are using controller method and model is huge :

    [HttpPost]
    public ActionResult AddOrUpdateConsumerFile(FileMetaDataModelView inputModel)
    {
        if (inputModel == null) return null;
     ....
    }

system throws exception like this "Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property. Parameter name: input"

Only changing Web.config settings is not enough to help in this case. You could additionally override mvc json serializer for supporting huge data model sizes or manually deserialize model from Request. Your controller method becomes:

   [HttpPost]
    public ActionResult AddOrUpdateConsumerFile()
    {
        FileMetaDataModelView inputModel = RequestManager.GetModelFromJsonRequest<FileMetaDataModelView>(HttpContext.Request);
        if (inputModel == null) return null;
        ......
    }

   public static T GetModelFromJsonRequest<T>(HttpRequestBase request)
    {
        string result = "";
        using (Stream req = request.InputStream)
        {
            req.Seek(0, System.IO.SeekOrigin.Begin);
            result = new StreamReader(req).ReadToEnd();
        }
        return JsonConvert.DeserializeObject<T>(result);
    }

None of the above worked out for me until I changed the Action as [HttpPost]. and made the ajax type as POST.

    [HttpPost]
    public JsonResult GetSelectedSignalData(string signal1,...)
    {
         JsonResult result = new JsonResult();
         var signalData = GetTheData();
         try
         {
              var serializer = new System.Web.Script.Serialization.JavaScriptSerializer { MaxJsonLength = Int32.MaxValue, RecursionLimit = 100 };

            result.Data = serializer.Serialize(signalData);
            return Json(result, JsonRequestBehavior.AllowGet);
            ..
            ..
            ...

    }

And the ajax call as

$.ajax({
    type: "POST",
    url: some_url,
    data: JSON.stringify({  signal1: signal1,.. }),
    contentType: "application/json; charset=utf-8",
    success: function (data) {
        if (data !== null) {
            setValue();
        }

    },
    failure: function (data) {
        $('#errMessage').text("Error...");
    },
    error: function (data) {
        $('#errMessage').text("Error...");
    }
});

    protected override JsonResult Json(object data, string contentType, System.Text.Encoding contentEncoding, JsonRequestBehavior behavior)
    {
        return new JsonResult()
        {
            Data = data,
            ContentType = contentType,
            ContentEncoding = contentEncoding,
            JsonRequestBehavior = behavior,
            MaxJsonLength = Int32.MaxValue
        };
    }

Was the fix for me in MVC 4.


No need for a custom class. This is all that is needed:

return new JsonResult { Data = Result, MaxJsonLength = Int32.MaxValue };

where Result is that data you wish to serialize.


I solved the issue by following this link

namespace System.Web.Mvc
{
public sealed class JsonDotNetValueProviderFactory : ValueProviderFactory
{
    public override IValueProvider GetValueProvider(ControllerContext controllerContext)
    {
        if (controllerContext == null)
            throw new ArgumentNullException("controllerContext");

        if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
            return null;

        var reader = new StreamReader(controllerContext.HttpContext.Request.InputStream);
        var bodyText = reader.ReadToEnd();

        return String.IsNullOrEmpty(bodyText) ? null : new DictionaryValueProvider<object>(JsonConvert.DeserializeObject<ExpandoObject>(bodyText, new ExpandoObjectConverter()), CultureInfo.CurrentCulture);
    }
}

}

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

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

        //Remove and JsonValueProviderFactory and add JsonDotNetValueProviderFactory
        ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().FirstOrDefault());
        ValueProviderFactories.Factories.Add(new JsonDotNetValueProviderFactory());
    }

Unfortunately the web.config setting is ignored by the default JsonResult implementation. So I guess you will need to implement a custom json result to overcome this issue.


Alternative ASP.NET MVC 5 Fix:

In my case the error was occurring during the request. Best approach in my scenario is modifying the actual JsonValueProviderFactory which applies the fix to the global project and can be done by editing the global.cs file as such.

JsonValueProviderConfig.Config(ValueProviderFactories.Factories);

add a web.config entry:

<add key="aspnet:MaxJsonLength" value="20971520" />

and then create the two following classes

public class JsonValueProviderConfig
{
    public static void Config(ValueProviderFactoryCollection factories)
    {
        var jsonProviderFactory = factories.OfType<JsonValueProviderFactory>().Single();
        factories.Remove(jsonProviderFactory);
        factories.Add(new CustomJsonValueProviderFactory());
    }
}

This is basically an exact copy of the default implementation found in System.Web.Mvc but with the addition of a configurable web.config appsetting value aspnet:MaxJsonLength.

public class CustomJsonValueProviderFactory : ValueProviderFactory
{

    /// <summary>Returns a JSON value-provider object for the specified controller context.</summary>
    /// <returns>A JSON value-provider object for the specified controller context.</returns>
    /// <param name="controllerContext">The controller context.</param>
    public override IValueProvider GetValueProvider(ControllerContext controllerContext)
    {
        if (controllerContext == null)
            throw new ArgumentNullException("controllerContext");

        object deserializedObject = CustomJsonValueProviderFactory.GetDeserializedObject(controllerContext);
        if (deserializedObject == null)
            return null;

        Dictionary<string, object> strs = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
        CustomJsonValueProviderFactory.AddToBackingStore(new CustomJsonValueProviderFactory.EntryLimitedDictionary(strs), string.Empty, deserializedObject);

        return new DictionaryValueProvider<object>(strs, CultureInfo.CurrentCulture);
    }

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

        string fullStreamString = (new StreamReader(controllerContext.HttpContext.Request.InputStream)).ReadToEnd();
        if (string.IsNullOrEmpty(fullStreamString))
            return null;

        var serializer = new JavaScriptSerializer()
        {
            MaxJsonLength = CustomJsonValueProviderFactory.GetMaxJsonLength()
        };
        return serializer.DeserializeObject(fullStreamString);
    }

    private static void AddToBackingStore(EntryLimitedDictionary backingStore, string prefix, object value)
    {
        IDictionary<string, object> strs = value as IDictionary<string, object>;
        if (strs != null)
        {
            foreach (KeyValuePair<string, object> keyValuePair in strs)
                CustomJsonValueProviderFactory.AddToBackingStore(backingStore, CustomJsonValueProviderFactory.MakePropertyKey(prefix, keyValuePair.Key), keyValuePair.Value);

            return;
        }

        IList lists = value as IList;
        if (lists == null)
        {
            backingStore.Add(prefix, value);
            return;
        }

        for (int i = 0; i < lists.Count; i++)
        {
            CustomJsonValueProviderFactory.AddToBackingStore(backingStore, CustomJsonValueProviderFactory.MakeArrayKey(prefix, i), lists[i]);
        }
    }

    private class EntryLimitedDictionary
    {
        private static int _maximumDepth;

        private readonly IDictionary<string, object> _innerDictionary;

        private int _itemCount;

        static EntryLimitedDictionary()
        {
            _maximumDepth = CustomJsonValueProviderFactory.GetMaximumDepth();
        }

        public EntryLimitedDictionary(IDictionary<string, object> innerDictionary)
        {
            this._innerDictionary = innerDictionary;
        }

        public void Add(string key, object value)
        {
            int num = this._itemCount + 1;
            this._itemCount = num;
            if (num > _maximumDepth)
            {
                throw new InvalidOperationException("The length of the string exceeds the value set on the maxJsonLength property.");
            }
            this._innerDictionary.Add(key, value);
        }
    }

    private static string MakeArrayKey(string prefix, int index)
    {
        return string.Concat(prefix, "[", index.ToString(CultureInfo.InvariantCulture), "]");
    }

    private static string MakePropertyKey(string prefix, string propertyName)
    {
        if (string.IsNullOrEmpty(prefix))
        {
            return propertyName;
        }
        return string.Concat(prefix, ".", propertyName);
    }

    private static int GetMaximumDepth()
    {
        int num;
        NameValueCollection appSettings = ConfigurationManager.AppSettings;
        if (appSettings != null)
        {
            string[] values = appSettings.GetValues("aspnet:MaxJsonDeserializerMembers");
            if (values != null && values.Length != 0 && int.TryParse(values[0], out num))
            {
                return num;
            }
        }
        return 1000;
    }

    private static int GetMaxJsonLength()
    {
        int num;
        NameValueCollection appSettings = ConfigurationManager.AppSettings;
        if (appSettings != null)
        {
            string[] values = appSettings.GetValues("aspnet:MaxJsonLength");
            if (values != null && values.Length != 0 && int.TryParse(values[0], out num))
            {
                return num;
            }
        }
        return 1000;
    }
}

If use Json.NET to generate the json string, it doesn't need to set MaxJsonLength value.

return new ContentResult()
{
    Content = Newtonsoft.Json.JsonConvert.SerializeObject(data),
    ContentType = "application/json",
};

You need to read from the configuration section manually before your code returns a JsonResult object. Simply read from web.config in single line:

        var jsonResult = Json(resultsForAjaxUI);
        jsonResult.MaxJsonLength = (ConfigurationManager.GetSection("system.web.extensions/scripting/webServices/jsonSerialization") as System.Web.Configuration.ScriptingJsonSerializationSection).MaxJsonLength;
        return jsonResult;

Be sure you defined configuration element in web.config


this worked for me

        JsonSerializerSettings json = new JsonSerializerSettings
        {
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore
        };
        var result = JsonConvert.SerializeObject(list, Formatting.Indented, json);
        return new JsonResult { Data = result, MaxJsonLength = int.MaxValue };

You can put this code in cshtml if you are returning view from controller and you want to increase the length of view bag data while encoding in json in cshtml

@{
    var jss = new System.Web.Script.Serialization.JavaScriptSerializer();
    jss.MaxJsonLength = Int32.MaxValue;
    var userInfoJson = jss.Serialize(ViewBag.ActionObj);
}

var dataJsonOnActionGrid1 = @Html.Raw(userInfoJson);

Now, dataJsonOnActionGrid1 will be accesible on js page and you will get proper result.

Thanks


You could also use ContentResult as suggested here instead of subclassing JsonResult.

var serializer = new JavaScriptSerializer { MaxJsonLength = Int32.MaxValue, RecursionLimit = 100 };

return new ContentResult()
{
    Content = serializer.Serialize(data),
    ContentType = "application/json",
};

You can try define in your LINQ expression only the field's that you will need.

Example. Imagine that you have an Model with Id, Name, Phone and Picture (byte array) and need to load from json into an select list.

LINQ Query:

var listItems = (from u in Users where u.name.Contains(term) select u).ToList();

The problem here is "select u" that get all fields. So, if you have big pictures, booomm.

How to solve? very, very simple.

var listItems = (from u in Users where u.name.Contains(term) select new {u.Id, u.Name}).ToList();

The best practices is select only the field that you will use.

Remember. This is a simple tip, but can help many ASP.NET MVC developpers.


I'm surprised no one has suggested using a result filter. This is the cleanest way to globally hook into the action/result pipeline:

public class JsonResultFilter : IResultFilter
{
    public int? MaxJsonLength { get; set; }

    public int? RecursionLimit { get; set; }

    public void OnResultExecuting(ResultExecutingContext filterContext)
    {
        if (filterContext.Result is JsonResult jsonResult)
        {
            // override properties only if they're not set
            jsonResult.MaxJsonLength = jsonResult.MaxJsonLength ?? MaxJsonLength;
            jsonResult.RecursionLimit = jsonResult.RecursionLimit ?? RecursionLimit;
        }
    }

    public void OnResultExecuted(ResultExecutedContext filterContext)
    {
    }
}

Then, register an instance of that class using GlobalFilters.Filters:

GlobalFilters.Filters.Add(new JsonResultFilter { MaxJsonLength = int.MaxValue });

Examples related to asp.net-mvc

Using Lato fonts in my css (@font-face) Better solution without exluding fields from Binding Vue.js get selected option on @change You must add a reference to assembly 'netstandard, Version=2.0.0.0 How to send json data in POST request using C# VS 2017 Metadata file '.dll could not be found The default XML namespace of the project must be the MSBuild XML namespace How to create roles in ASP.NET Core and assign them to users? The model item passed into the dictionary is of type .. but this dictionary requires a model item of type How to use npm with ASP.NET Core

Examples related to exception

Connection Java-MySql : Public Key Retrieval is not allowed How to print an exception in Python 3? ASP.NET Core Web API exception handling Catching FULL exception message How to get exception message in Python properly What does "Fatal error: Unexpectedly found nil while unwrapping an Optional value" mean? what does Error "Thread 1:EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)" mean? Argument Exception "Item with Same Key has already been added" The given key was not present in the dictionary. Which key? sql try/catch rollback/commit - preventing erroneous commit after rollback

Examples related to serialization

laravel Unable to prepare route ... for serialization. Uses Closure TypeError: Object of type 'bytes' is not JSON serializable Best way to save a trained model in PyTorch? Convert Dictionary to JSON in Swift Java: JSON -> Protobuf & back conversion Understanding passport serialize deserialize How to generate serial version UID in Intellij Parcelable encountered IOException writing serializable object getactivity() Task not serializable: java.io.NotSerializableException when calling function outside closure only on classes not objects Cannot deserialize the JSON array (e.g. [1,2,3]) into type ' ' because type requires JSON object (e.g. {"name":"value"}) to deserialize correctly

Examples related to jsonresult

Fastest way to check if a string is JSON in PHP? MaxJsonLength exception in ASP.NET MVC during JavaScriptSerializer