asp.net-mvc JavaScriptSerializer 期间 ASP.NET MVC 中的 MaxJsonLength 异常
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5692836/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
MaxJsonLength exception in ASP.NET MVC during JavaScriptSerializer
提问by Martin Buberl
In one of my controller actions I am returning a very large JsonResult
to fill a grid.
在我的控制器操作之一中,我返回了一个非常大JsonResult
的填充网格。
I am getting the following InvalidOperationException
exception:
我收到以下InvalidOperationException
异常:
Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property.
使用 JSON JavaScriptSerializer 进行序列化或反序列化时出错。字符串的长度超过了 maxJsonLength 属性上设置的值。
Setting the maxJsonLength
property in the web.config
to a higher value unfortunately does not show any effect.
不幸的是,将 中的maxJsonLength
属性设置web.config
为更高的值并没有显示任何效果。
<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 thisSO answer.
我不想像这个SO 答案中提到的那样将它作为字符串传回。
In my research I came across thisblog post where writing an own ActionResult
(e.g. LargeJsonResult : JsonResult
) is recommended to bypass this behaviour.
在我的研究中,我遇到了这篇博客文章,其中建议编写自己的ActionResult
(例如LargeJsonResult : JsonResult
)来绕过这种行为。
Is this then the only solution?
Is this a bug in ASP.NET MVC?
Am I missing something?
那么这是唯一的解决方案吗?
这是 ASP.NET MVC 中的错误吗?
我错过了什么吗?
Any help would be most appreciated.
非常感激任何的帮助。
回答by Orion Edwards
It appears this has been fixed in MVC4.
这似乎已在 MVC4 中修复。
You can do this, which worked well for me:
你可以这样做,这对我来说效果很好:
public ActionResult SomeControllerAction()
{
var jsonResult = Json(veryLargeCollection, JsonRequestBehavior.AllowGet);
jsonResult.MaxJsonLength = int.MaxValue;
return jsonResult;
}
回答by SliverNinja - MSFT
You could also use ContentResult
as suggested hereinstead of subclassing JsonResult
.
您也可以ContentResult
按照此处的建议使用,而不是使用 subclassing JsonResult
。
var serializer = new JavaScriptSerializer { MaxJsonLength = Int32.MaxValue, RecursionLimit = 100 };
return new ContentResult()
{
Content = serializer.Serialize(data),
ContentType = "application/json",
};
回答by Darin Dimitrov
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.
不幸的是,默认的 JsonResult 实现忽略了 web.config 设置。所以我想你需要实现一个自定义的 json 结果来解决这个问题。
回答by John
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.
Result
您希望序列化的数据在哪里。
回答by AechoLiu
回答by Sajjad Ali Khan
I solved the issue by following thislink
我通过点击这个链接解决了这个问题
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());
}
回答by Maxim Gershkovich
Alternative ASP.NET MVC 5 Fix:
替代 ASP.NET MVC 5 修复:
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.
在我的情况下,错误发生在请求期间。在我的场景中,最好的方法是修改将JsonValueProviderFactory
修复应用到全局项目的实际值,并且可以通过这样编辑global.cs
文件来完成。
JsonValueProviderConfig.Config(ValueProviderFactories.Factories);
add a web.config entry:
添加一个 web.config 条目:
<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
.
这基本上是在 中找到的默认实现的精确副本,System.Web.Mvc
但添加了可配置的 web.config 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;
}
}
回答by glanes
You can try define in your LINQ expression only the field's that you will need.
您可以尝试在 LINQ 表达式中仅定义您需要的字段。
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.
例子。想象一下,您有一个带有 Id、Name、Phone 和Picture(字节数组)的模型,并且需要从 json 加载到一个选择列表中。
LINQ Query:
LINQ 查询:
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.
这里的问题是获取所有字段的“选择 u”。所以,如果你有大图,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.
记住。这是一个简单的技巧,但可以帮助许多 ASP.NET MVC 开发人员。
回答by Ronnie Overby
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
:
GlobalFilters.Filters.Add(new JsonResultFilter { MaxJsonLength = int.MaxValue });
回答by eaglei22
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.
是 MVC 4 中对我的修复。