[ArgumentException: 使用 JSON JavaScriptSerializer 序列化或還原序列化期間發生錯誤。字符串的長度超過在 maxJsonLength 屬性上設定的值。 參數名稱: input] System.Web.Script.Serialization.JavaScriptSerializer.Deserialize(JavaScriptSerializer serializer, String input, Type type, Int32 depthLimit) +168 System.Web.Mvc.JsonValueProviderFactory.GetDeserializedObject(ControllerContext controllerContext) +213 System.Web.Mvc.JsonValueProviderFactory.GetValueProvider(ControllerContext controllerContext) +16 System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext) +69 System.Web.Mvc.ControllerBase.get_ValueProvider() +30
因爲前端 Post 到 Action 的參數太大,超過了2M,還沒進入後臺的 Action 方法就報錯了。這個問題困擾了好久,一直未解決。網上找了幾個方法都無效。html
在 web.config 中加入這些,沒有做用:前端
<appSettings> <add key="aspnet:MaxJsonDeserializerMembers" value="2147483647" /> <add key="aspnet:UpdatePanelMaxScriptLength" value="2147483647" /> </appSettings>
在 web.config 中加入這些,也沒有做用:java
<system.web.extensions> <scripting> <webServices> <jsonSerialization maxJsonLength="2147483647"> </jsonSerialization> </webServices> </scripting> </system.web.extensions>
仔細看了一下異常信息,發現,是在System.Web.Mvc.JsonValueProviderFactory 裏調用的 JavaScriptSerializer:web
因而查了一下 ,發現 JsonValueProviderFactory 在 System.Web.Mvc.dll 程序集裏的:json
反編譯 System.Web.Mvc.dll 找到 JsonValueProviderFactory 類:app
using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Configuration; using System.Globalization; using System.IO; using System.Web.Mvc.Properties; using System.Web.Script.Serialization; namespace System.Web.Mvc { public sealed class JsonValueProviderFactory : ValueProviderFactory { private class EntryLimitedDictionary { private static int _maximumDepth = JsonValueProviderFactory.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 > JsonValueProviderFactory.EntryLimitedDictionary._maximumDepth) { throw new InvalidOperationException(MvcResources.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; } } private static void AddToBackingStore(JsonValueProviderFactory.EntryLimitedDictionary backingStore, string prefix, object value) { IDictionary<string, object> dictionary = value as IDictionary<string, object>; if (dictionary != null) { foreach (KeyValuePair<string, object> current in dictionary) { JsonValueProviderFactory.AddToBackingStore(backingStore, JsonValueProviderFactory.MakePropertyKey(prefix, current.Key), current.Value); } return; } IList list = value as IList; if (list != null) { for (int i = 0; i < list.Count; i++) { JsonValueProviderFactory.AddToBackingStore(backingStore, JsonValueProviderFactory.MakeArrayKey(prefix, i), list[i]); } return; } backingStore.Add(prefix, value); } private static object GetDeserializedObject(ControllerContext controllerContext) { if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase)) { return null; } StreamReader streamReader = new StreamReader(controllerContext.HttpContext.Request.InputStream); string text = streamReader.ReadToEnd(); if (string.IsNullOrEmpty(text)) { return null; } // 問題就出在這裏,沒有給 javaScriptSerializer.MaxJsonLength 賦值,其默認值是 2097152 字節,即2M JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer(); return javaScriptSerializer.DeserializeObject(text); } public override IValueProvider GetValueProvider(ControllerContext controllerContext) { if (controllerContext == null) { throw new ArgumentNullException("controllerContext"); } object deserializedObject = JsonValueProviderFactory.GetDeserializedObject(controllerContext); if (deserializedObject == null) { return null; } Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); JsonValueProviderFactory.EntryLimitedDictionary backingStore = new JsonValueProviderFactory.EntryLimitedDictionary(dictionary); JsonValueProviderFactory.AddToBackingStore(backingStore, string.Empty, deserializedObject); return new DictionaryValueProvider<object>(dictionary, CultureInfo.CurrentCulture); } private static string MakeArrayKey(string prefix, int index) { return prefix + "[" + index.ToString(CultureInfo.InvariantCulture) + "]"; } private static string MakePropertyKey(string prefix, string propertyName) { if (!string.IsNullOrEmpty(prefix)) { return prefix + "." + propertyName; } return propertyName; } } }
在 JavaScriptSerializer 沒有設置 MaxJsonLength,默認值是 2097152 字節,即2M。 ide
解決此問題的方法就是 把 javaScriptSerializer.MaxJsonLength = int.MaxValue; (int.MaxValue 值是 2147483647 字節,即2048M)this
本身重寫類 JsonValueProviderFactory 命名爲 MyJsonValueProviderFactory:spa
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.Globalization;
using System.IO;
using System.Web.Mvc;
using System.Web.Mvc.Properties;
using System.Web.Script.Serialization;
namespace XXX
{
public sealed class MyJsonValueProviderFactory : ValueProviderFactory
{
private class EntryLimitedDictionary
{
private static int _maximumDepth = 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 > _maximumDepth)
{
//throw new InvalidOperationException(MvcResources.JsonValueProviderFactory_RequestTooLarge);
throw new InvalidOperationException("itemCount is over maximumDepth");
}
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;
}
}
private static void AddToBackingStore(EntryLimitedDictionary backingStore, string prefix, object value)
{
IDictionary<string, object> dictionary = value as IDictionary<string, object>;
if (dictionary != null)
{
foreach (KeyValuePair<string, object> current in dictionary)
{
AddToBackingStore(backingStore, MakePropertyKey(prefix, current.Key), current.Value);
}
return;
}
IList list = value as IList;
if (list != null)
{
for (int i = 0; i < list.Count; i++)
{
AddToBackingStore(backingStore, MakeArrayKey(prefix, i), list[i]);
}
return;
}
backingStore.Add(prefix, value);
}
private static object GetDeserializedObject(ControllerContext controllerContext)
{
if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
{
return null;
}
StreamReader streamReader = new StreamReader(controllerContext.HttpContext.Request.InputStream);
string text = streamReader.ReadToEnd();
if (string.IsNullOrEmpty(text))
{
return null;
}
JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
// 解決這個問題:
// 使用 JSON JavaScriptSerializer 序列化或還原序列化期間發生錯誤。字符串的長度超過在 maxJsonLength 屬性上設定的值。
javaScriptSerializer.MaxJsonLength = int.MaxValue;
// ----------------------------------------
return javaScriptSerializer.DeserializeObject(text);
}
public override IValueProvider GetValueProvider(ControllerContext controllerContext)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
object deserializedObject = GetDeserializedObject(controllerContext);
if (deserializedObject == null)
{
return null;
}
Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
EntryLimitedDictionary backingStore = new EntryLimitedDictionary(dictionary);
AddToBackingStore(backingStore, string.Empty, deserializedObject);
return new DictionaryValueProvider<object>(dictionary, CultureInfo.CurrentCulture);
}
private static string MakeArrayKey(string prefix, int index)
{
return prefix + "[" + index.ToString(CultureInfo.InvariantCulture) + "]";
}
private static string MakePropertyKey(string prefix, string propertyName)
{
if (!string.IsNullOrEmpty(prefix))
{
return prefix + "." + propertyName;
}
return propertyName;
}
}
}
而後在 Global.asax 中的 Application_Start() 方法裏,加入以下代碼,用 MyJsonValueProviderFactory 類代替 System.Web.Mvc.dll 程序集中的 JsonValueProviderFactory 類。htm
ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().FirstOrDefault()); ValueProviderFactories.Factories.Add(new MyJsonValueProviderFactory());
至此,.NET MVC 超出 maxJsonLength 的問題終於解決了!