【问题标题】:MVC 5 Increase Max JSON Length in POST RequestMVC 5 增加 POST 请求中的最大 JSON 长度
【发布时间】:2016-12-15 15:28:17
【问题描述】:

我正在向正文中包含大量 JSON 数据的 MVC 控制器发送 POST 请求,它抛出以下内容:

ArgumentException: 使用序列化或反序列化时出错 JSON JavaScriptSerializer。字符串长度超过 maxJsonLength 属性上设置的值。 参数名称:输入

为了解决这个问题,我尝试了许多Web.Config 解决方案。即:

<system.web> 
...
<httpRuntime maxRequestLength="2147483647" />
</system.web>

...

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

现在,我正在与之通信的控制器在其自己的区域中,具有自己的 Web.Config。我已经尝试将上述内容单独放置在根目录或区域的 Web.Config 中,但两者都不起作用。当我在同一个控制器中调试不同的方法时,我会得到默认的 JSON 最大长度:

Console.WriteLine(new ScriptingJsonSerializationSection().MaxJsonLength);
// 102400

这是我要发布的方法:

[HttpPost]
public JsonResult MyMethod (string data = "") { //... }

如何增加 MVC 控制器的最大 JSON 长度,以便我的请求可以成功到达方法?

编辑:添加&lt;httpRuntime maxRequestLength="2147483647" /&gt;

【问题讨论】:

  • 您是否尝试在 web config 中增加响应长度。参考stackoverflow.com/questions/16436533/…
  • 是的,我的 Web.Config 中也有 &lt;httpRuntime maxRequestLength="2147483647" /&gt;
  • 如果响应太大,您不能流式传输响应吗?
  • @aiokos 在这些情况下,除了 maxJsonLength 和 maxRequestLength 之外,您通常看到的唯一其他解决方案是 web.config 的 appSettings 部分中的 &lt;add key="aspnet:MaxJsonDeserializerMembers" value="2147483644" /&gt;。试试看。
  • 这与返回的 JSON 的大小无关,因为在我的方法主体被调用之前就抛出了异常。问题是默认 MVC 模型绑定器的 JSON 最大长度。我在 POST 正文中发送的 JSON 大小约为 2mb。

标签: c# json asp.net-mvc-5


【解决方案1】:

因此,虽然这是一个相当令人不快的解决方案,但我通过手动读取请求流而不是依赖 MVC 的模型绑定器来解决问题。

比如我的方法

[HttpPost]
public JsonResult MyMethod (string data = "") { //... }

成为

[HttpPost]
public JsonResult MyMethod () {
    Stream req = Request.InputStream;
    req.Seek(0, System.IO.SeekOrigin.Begin);
    string json = new StreamReader(req).ReadToEnd();
    MyModel model = JsonConvert.DeserializeObject<MyModel>(json);
    // use model...
}

这样我可以使用 JSON.NET 并通过 MVC 的默认解串器绕过 JSON 最大长度限制。

为了适应这个解决方案,我建议创建一个自定义 JsonResult 工厂,它将替换 Application_Start() 中的旧工厂。

【讨论】:

  • 我有一个相当大的 JSON 字符串,它发送 22 个不同的事务。我将它们设置为我的 json 格式的页面。如果上述解决方案不适合您,您可以尝试一下。
  • 这是个好主意。我想我现在会坚持使用这个解决方案,直到我用 JSON.NET 覆盖默认的 MVC JSON 序列化程序。这种规模的请求一开始不太可能发生。
  • 我正准备将所有内容切换到另一种技术,使用 angular-base64-upload,直到我发现这个解决方法,因为 web.config 大小设置都没有任何效果。谢谢!。
  • 我喜欢这个 hack。测试了上述所有 web.config 设置,但没有任何帮助。这成功了!
  • 与上面的@gurkan 相同——我尝试了其他所有方法,这是唯一有效的方法。
【解决方案2】:

问题:

问题出在System.Web.Mvc 命名空间中的JsonValueProviderFactory 类中。实际上,如果你反编译System.Web.Mvc.dll 并找到JsonValueProviderFactory 类,你会看到在GetDeserializedObject 方法中它使用了JavaScriptSerializer,而没有为MaxJsonLength 设置任何值:

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;
    }
    // The problem is here, not given. javaScriptSerializer.MaxJsonLength The default value is 2097152 bytes, that is 2. M
    JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
    return javaScriptSerializer.DeserializeObject(text);
}

解决方案: 您可以重写JsonValueProviderFactory 类并设置javaScriptSerializer.MaxJsonLength,然后在Global.asax 中的Application_Start() 方法中替换该类,如下所示:

ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().FirstOrDefault());
ValueProviderFactories.Factories.Add(new MyJsonValueProviderFactory());

这是完整的工作代码:

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();
            // To solve this problem:
            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;
        }
    }
}

参考资料: https://www.fatalerrors.org/a/net-mvc-json-javascriptserializer-string-exceeds-the-maxjsonlength.html

【讨论】:

    【解决方案3】:
    <system.web>
        <httpRuntime  maxRequestLength="1048576" />  
    </system.web>
    
    <system.webServer>
        <security>
          <requestFiltering>
            <requestLimits maxAllowedContentLength="1073741824" />
          </requestFiltering>
        </security>
    </system.webServer>
    

    【讨论】:

      猜你喜欢
      • 2015-05-08
      • 1970-01-01
      • 2016-05-24
      • 2015-09-29
      • 1970-01-01
      • 2014-10-16
      • 1970-01-01
      • 2011-04-20
      相关资源
      最近更新 更多