我正在使用一些使用ASP设计的应用程序。NET MVC。确实花了很多时间试图解决一些问题,但不知道该怎么解决。
如下所示,对于大型JSON的类似代码将抛出异常:"使用JSON JavaScriptSerializer进行序列化或反序列化时出错。字符串的长度超过了在maxJsonLength属性上设置的值。"示例:
$http.post('/API/PostData',aoData)...
其中aoData等于JSON的3K数组等
在stackoverflow上提出的许多问题中添加了一些解决方案。
确实通过以下方式解决了这个问题:
- 从ValueProviderFactory中删除JsonValueProviderFactory。工厂
- 并添加原始类的副本,只需简单的修改,例如:
示例:
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;
}
}
}
这就解决了maxJsonLength的问题。太棒了但是
若JSON包含名为ACTION的属性,则控制器将获取正在更改的数据。ACTION属性包含控制器动作的名称,而不是"ACTION";MAR";。LargeJsonValueProviderFactory类不会更改ACION属性的值。但如果上面显示的LargeJsonValueProviderFactory类不是使用问题就消失了。
示例:
{编号:1200,动作:";MAR";,。。。。。}
public ActionResult Save(PrsentationEntity aoData)
{
aoData.NR equals 1200 - OK
aoData.ACTION equals "Save" -Should be "MAR"
你知道我为什么会有这个问题吗?
问候Marcin
tl;dr
配置应用程序时,应将原始JsonValueProviderFactory
替换为自定义LargeJsonValueProviderFactory
,而不是添加到集合的末尾。
长版本
你说你通过解决了这个问题
- 从
ValueProviderFactories.Factories
中删除JsonValueProviderFactory
- 并添加原始类的副本,只需简单的修改,例如:
这就是出现问题的原因。
ValueProviderFactories.Factories
上工厂的顺序确实很重要,但通常不会讨论。
最初的订单是:
private static readonly ValueProviderFactoryCollection _factories = new ValueProviderFactoryCollection()
{
new ChildActionValueProviderFactory(),
new FormValueProviderFactory(),
new JsonValueProviderFactory(),
new RouteDataValueProviderFactory(),
new QueryStringValueProviderFactory(),
new HttpFileCollectionValueProviderFactory(),
new JQueryFormValueProviderFactory()
};
如果您只是将新的提供程序添加到集合的末尾,那么如果其他提供程序中的一个执行此操作,则不会使用它(在这种情况下,似乎使用了RouteDataValueProviderFactory
(。