使用修改的JsonValueProviderFactory解决maxJsonLength异常后,原始数据发生了更改



我正在使用一些使用ASP设计的应用程序。NET MVC。确实花了很多时间试图解决一些问题,但不知道该怎么解决。

如下所示,对于大型JSON的类似代码将抛出异常:"使用JSON JavaScriptSerializer进行序列化或反序列化时出错。字符串的长度超过了在maxJsonLength属性上设置的值。"示例:

$http.post('/API/PostData',aoData)...

其中aoData等于JSON的3K数组等

在stackoverflow上提出的许多问题中添加了一些解决方案。

确实通过以下方式解决了这个问题:

  1. 从ValueProviderFactory中删除JsonValueProviderFactory。工厂
  2. 并添加原始类的副本,只需简单的修改,例如:

示例:

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,而不是添加到集合的末尾。


长版本

你说你通过解决了这个问题

  1. ValueProviderFactories.Factories中删除JsonValueProviderFactory
  2. 并添加原始类的副本,只需简单的修改,例如:

这就是出现问题的原因。

ValueProviderFactories.Factories上工厂的顺序确实很重要,但通常不会讨论。

最初的订单是:

private static readonly ValueProviderFactoryCollection _factories = new ValueProviderFactoryCollection()
{
new ChildActionValueProviderFactory(),
new FormValueProviderFactory(),
new JsonValueProviderFactory(),
new RouteDataValueProviderFactory(),
new QueryStringValueProviderFactory(),
new HttpFileCollectionValueProviderFactory(),
new JQueryFormValueProviderFactory()
};

如果您只是将新的提供程序添加到集合的末尾,那么如果其他提供程序中的一个执行此操作,则不会使用它(在这种情况下,似乎使用了RouteDataValueProviderFactory(。

最新更新