我正在使用jQuery的自动完成功能。当我试图检索超过17000条记录的列表(每个记录不会超过10个字符长度)时,它超过了长度并抛出错误:

异常信息: 异常类型:InvalidOperationException 异常消息:使用JSON JavaScriptSerializer进行序列化或反序列化时出错。字符串的长度超过maxJsonLength属性设置的值。

我可以在web.config中设置maxJsonLength的无限长度吗?如果不是,我可以设置的最大长度是多少?


当前回答

选择ASP。NET MVC 5修复:

(我的答案与上面的mfc答案相似,只是有一些小变化)

我还没准备好改用Json。NET还没有,在我的情况下,错误发生在请求期间。在我的场景中,最好的方法是修改实际的JsonValueProviderFactory,它将修复应用到全局项目,可以通过编辑global.cs文件来完成。

JsonValueProviderConfig.Config(ValueProviderFactories.Factories);

添加一个网页。配置项:

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

然后创建以下两个类

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

这基本上是在System.Web.Mvc中找到的默认实现的精确副本,但添加了可配置的web。配置appsetting值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;
    }
}

其他回答

问题是你是否真的需要返回17k条记录?您打算如何处理浏览器中的所有数据?用户无论如何都不会滚动17000行。

更好的方法是只检索“前几条”记录,并根据需要加载更多记录。

对于那些有问题的MVC3 JSON自动反序列化的模型绑定和太大,这里有一个解决方案。

将JsonValueProviderFactory类的代码从MVC3源代码复制到一个新类中。 添加一行来更改对象反序列化之前的最大JSON长度。 用修改后的新类替换JsonValueProviderFactory类。

感谢http://blog.naver.com/techshare/100145191355和https://gist.github.com/DalSoft/1588818为我指明了正确的方向,如何做到这一点。第一个站点上的最后一个链接包含解决方案的完整源代码。

我们不需要任何服务器端更改。你只能通过web修改这个问题。配置文件 这对我很有帮助。试试这个

<appSettings>
 <add key="aspnet:MaxJsonDeserializerMembers" value="2147483647" />
<add key="aspnet:UpdatePanelMaxScriptLength" value="2147483647" />
</appSettings>  

and   

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

来点属性魔法怎么样?

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class MaxJsonSizeAttribute : ActionFilterAttribute
{
    // Default: 10 MB worth of one byte chars
    private int maxLength = 10 * 1024 * 1024;

    public int MaxLength
    {
        set
        {
            if (value < 0) throw new ArgumentOutOfRangeException("value", "Value must be at least 0.");

            maxLength = value;
        }
        get { return maxLength; }
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        JsonResult json = filterContext.Result as JsonResult;
        if (json != null)
        {
            if (maxLength == 0)
            {
                json.MaxJsonLength = int.MaxValue;
            }
            else
            {
                json.MaxJsonLength = maxLength;
            }
        }
    }
}

然后,您可以使用全局过滤器配置或控制器/动作在全局中应用它。

似乎没有“无限”的价值。默认值是2097152个字符,相当于4 MB的Unicode字符串数据。

正如已经观察到的,在浏览器中很难很好地使用17000条记录。如果您正在呈现一个聚合视图,那么在服务器上进行聚合并在浏览器中只传输摘要可能会更有效。例如,考虑一个文件系统浏览器,我们只看到树的顶部,然后在向下钻取时发出进一步的请求。每个请求中返回的记录数量相对较少。树视图表示可以很好地用于大型结果集。