Can I set an unlimited length for maxJsonLength in web.config?

后端 未结 29 3256
礼貌的吻别
礼貌的吻别 2020-11-21 06:43

I am using the autocomplete feature of jQuery. When I try to retrieve the list of more then 17000 records (each won\'t have more than 10 char length), it\'s exceeding the le

相关标签:
29条回答
  • 2020-11-21 07:30

    If you are using MVC 4, be sure to check out this answer as well.


    If you are still receiving the error:

    • after setting the maxJsonLength property to its maximum value in web.config
    • and you know that your data's length is less than this value
    • and you are not utilizing a web service method for the JavaScript serialization

    your problem is is likely that:

    The value of the MaxJsonLength property applies only to the internal JavaScriptSerializer instance that is used by the asynchronous communication layer to invoke Web services methods. (MSDN: ScriptingJsonSerializationSection.MaxJsonLength Property)

    Basically, the "internal" JavaScriptSerializer respects the value of maxJsonLength when called from a web method; direct use of a JavaScriptSerializer (or use via an MVC action-method/Controller) does not respect the maxJsonLength property, at least not from the systemWebExtensions.scripting.webServices.jsonSerialization section of web.config.

    As a workaround, you can do the following within your Controller (or anywhere really):

    var serializer = new JavaScriptSerializer();
    
    // For simplicity just use Int32's max value.
    // You could always read the value from the config section mentioned above.
    serializer.MaxJsonLength = Int32.MaxValue;
    
    var resultData = new { Value = "foo", Text = "var" };
    var result = new ContentResult{
        Content = serializer.Serialize(resultData),
        ContentType = "application/json"
    };
    return result;
    

    This answer is my interpretation of this asp.net forum answer.

    0 讨论(0)
  • 2020-11-21 07:33

    Fix for ASP.NET MVC: if you want to fix it only for particular action that is causing the problem then change this code:

    public JsonResult GetBigJson()
    {
        var someBigObject = GetBigObject();
        return Json(someBigObject);
    }
    

    to this:

    public JsonResult GetBigJson()
    {
        var someBigObject = GetBigObject();
        return new JsonResult()
        {
            Data = someBigObject,
            JsonRequestBehavior = JsonRequestBehavior.DenyGet,
            MaxJsonLength = int.MaxValue
        };
    }
    

    And the functionality should be same, you can just return bigger JSON as response.


    Explanation based on ASP.NET MVC source code: you can check what Controller.Json method does in ASP.NET MVC source code

    protected internal JsonResult Json(object data)
    {
        return Json(data, null /* contentType */, null /* contentEncoding */, JsonRequestBehavior.DenyGet);
    }
    

    It is calling other Controller.Json method:

    protected internal virtual JsonResult Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior)
    {
        return new JsonResult
        {
            Data = data,
            ContentType = contentType,
            ContentEncoding = contentEncoding,
            JsonRequestBehavior = behavior
        };
    }
    

    where passed contentType and contentEncoding object are null. So basically calling return Json(object) in controller is equivalent to calling return new JsonResult { Data = object, JsonRequestBehavior = sonRequestBehavior.DenyGet }. You can use second form and parameterize JsonResult.

    So what happens when you set MaxJsonLength property (by default it's null)? It's passed down to JavaScriptSerializer.MaxJsonLength property and then JavaScriptSerializer.Serialize method is called :

    JavaScriptSerializer serializer = new JavaScriptSerializer();
    if (MaxJsonLength.HasValue)
    {
        serializer.MaxJsonLength = MaxJsonLength.Value;
    }
    
    if (RecursionLimit.HasValue)
    {
        serializer.RecursionLimit = RecursionLimit.Value;
    }
    
    response.Write(serializer.Serialize(Data));
    

    And when you don't set MaxJsonLenght property of serializer then it takes default value which is just 2MB.

    0 讨论(0)
  • 2020-11-21 07:34

    I was having this problem in ASP.NET Web Forms. It was completely ignoring the web.config file settings so I did this:

            JavaScriptSerializer serializer = new JavaScriptSerializer();
    
            serializer.MaxJsonLength = Int32.MaxValue; 
    
            return serializer.Serialize(response);
    

    Of course overall this is terrible practice. If you are sending this much data in a web service call you should look at a different approach.

    0 讨论(0)
  • 2020-11-21 07:34

    I followed vestigal's answer and got to this solution:

    When I needed to post a large json to an action in a controller, I would get the famous "Error during deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property.\r\nParameter name: input value provider".

    What I did is create a new ValueProviderFactory, LargeJsonValueProviderFactory, and set the MaxJsonLength = Int32.MaxValue in the GetDeserializedObject method

    public sealed class LargeJsonValueProviderFactory : ValueProviderFactory
    {
    private static void AddToBackingStore(LargeJsonValueProviderFactory.EntryLimitedDictionary backingStore, string prefix, object value)
    {
        IDictionary<string, object> dictionary = value as IDictionary<string, object>;
        if (dictionary != null)
        {
            foreach (KeyValuePair<string, object> keyValuePair in (IEnumerable<KeyValuePair<string, object>>) dictionary)
                LargeJsonValueProviderFactory.AddToBackingStore(backingStore, LargeJsonValueProviderFactory.MakePropertyKey(prefix, keyValuePair.Key), keyValuePair.Value);
        }
        else
        {
            IList list = value as IList;
            if (list != null)
            {
                for (int index = 0; index < list.Count; ++index)
                    LargeJsonValueProviderFactory.AddToBackingStore(backingStore, LargeJsonValueProviderFactory.MakeArrayKey(prefix, index), list[index]);
            }
            else
                backingStore.Add(prefix, value);
        }
    }
    
    private static object GetDeserializedObject(ControllerContext controllerContext)
    {
        if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
            return (object) null;
        string end = new StreamReader(controllerContext.HttpContext.Request.InputStream).ReadToEnd();
        if (string.IsNullOrEmpty(end))
            return (object) null;
    
        var serializer = new JavaScriptSerializer {MaxJsonLength = Int32.MaxValue};
    
        return serializer.DeserializeObject(end);
    }
    
    /// <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 = LargeJsonValueProviderFactory.GetDeserializedObject(controllerContext);
        if (deserializedObject == null)
            return (IValueProvider) null;
        Dictionary<string, object> dictionary = new Dictionary<string, object>((IEqualityComparer<string>) StringComparer.OrdinalIgnoreCase);
        LargeJsonValueProviderFactory.AddToBackingStore(new LargeJsonValueProviderFactory.EntryLimitedDictionary((IDictionary<string, object>) dictionary), string.Empty, deserializedObject);
        return (IValueProvider) new DictionaryValueProvider<object>((IDictionary<string, object>) dictionary, CultureInfo.CurrentCulture);
    }
    
    private static string MakeArrayKey(string prefix, int index)
    {
        return prefix + "[" + index.ToString((IFormatProvider) CultureInfo.InvariantCulture) + "]";
    }
    
    private static string MakePropertyKey(string prefix, string propertyName)
    {
        if (!string.IsNullOrEmpty(prefix))
            return prefix + "." + propertyName;
        return propertyName;
    }
    
    private class EntryLimitedDictionary
    {
        private static int _maximumDepth = LargeJsonValueProviderFactory.EntryLimitedDictionary.GetMaximumDepth();
        private readonly IDictionary<string, object> _innerDictionary;
        private int _itemCount;
    
        public EntryLimitedDictionary(IDictionary<string, object> innerDictionary)
        {
            this._innerDictionary = innerDictionary;
        }
    
        public void Add(string key, object value)
        {
            if (++this._itemCount > LargeJsonValueProviderFactory.EntryLimitedDictionary._maximumDepth)
                throw new InvalidOperationException("JsonValueProviderFactory_RequestTooLarge");
            this._innerDictionary.Add(key, value);
        }
    
        private static int GetMaximumDepth()
        {
            NameValueCollection appSettings = ConfigurationManager.AppSettings;
            if (appSettings != null)
            {
                string[] values = appSettings.GetValues("aspnet:MaxJsonDeserializerMembers");
                int result;
                if (values != null && values.Length > 0 && int.TryParse(values[0], out result))
                    return result;
            }
            return 1000;
         }
      }
    }
    

    Then, in the Application_Start method from Global.asax.cs, replace the ValueProviderFactory with the new one:

    protected void Application_Start()
    {
        ...
    
        //Add LargeJsonValueProviderFactory
        ValueProviderFactory jsonFactory = null;
        foreach (var factory in ValueProviderFactories.Factories)
        {
            if (factory.GetType().FullName == "System.Web.Mvc.JsonValueProviderFactory")
            {
                jsonFactory = factory;
                break;
            }
        }
    
        if (jsonFactory != null)
        {
            ValueProviderFactories.Factories.Remove(jsonFactory);
        }
    
        var largeJsonValueProviderFactory = new LargeJsonValueProviderFactory();
        ValueProviderFactories.Factories.Add(largeJsonValueProviderFactory);
    }
    
    0 讨论(0)
  • 2020-11-21 07:36

    In MVC 4 you can do:

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

    in your controller.

    Addition:

    For anyone puzzled by the parameters you need to specify, a call could look like this:

    Json(
        new {
            field1 = true,
            field2 = "value"
            },
        "application/json",
        Encoding.UTF8,
        JsonRequestBehavior.AllowGet
    );
    
    0 讨论(0)
  • 2020-11-21 07:36

    I fixed it.

    //your Json data here
    string json_object="........";
    JavaScriptSerializer jsJson = new JavaScriptSerializer();
    jsJson.MaxJsonLength = 2147483644;
    MyClass obj = jsJson.Deserialize<MyClass>(json_object);
    

    It works very well.

    0 讨论(0)
提交回复
热议问题