• .NET MVC JSON JavaScriptSerializer 字符串的长度超过 maxJsonLength 值问题的解决


    1 [ArgumentException: 使用 JSON JavaScriptSerializer 序列化或还原序列化期间发生错误。字符串的长度超过在 maxJsonLength 属性上设定的值。
    2 参数名称: input]
    3    System.Web.Script.Serialization.JavaScriptSerializer.Deserialize(JavaScriptSerializer serializer, String input, Type type, Int32 depthLimit) +168
    4    System.Web.Mvc.JsonValueProviderFactory.GetDeserializedObject(ControllerContext controllerContext) +213
    5    System.Web.Mvc.JsonValueProviderFactory.GetValueProvider(ControllerContext controllerContext) +16
    6    System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext) +69
    7    System.Web.Mvc.ControllerBase.get_ValueProvider() +30  

    于前端 Post 到 Action 的参数太大,超过了2M,还没进入后台的 Action 方法就报错了。这个问题困扰了很久,一直未解决。网上找了几个方法都无效。

    在 web.config 中加入这些,没有作用:

     
    1
    2
    3
    4
    <appSettings>
      <add key="aspnet:MaxJsonDeserializerMembers" value="2147483647" />
      <add key="aspnet:UpdatePanelMaxScriptLength" value="2147483647" />
    </appSettings>

    在 web.config 中加入这些,也没有作用:

     
    1
    2
    3
    4
    5
    6
    7
    8
    <system.web.extensions>
      <scripting>
        <webServices>
          <jsonSerialization maxJsonLength="2147483647">
          </jsonSerialization>
        </webServices>
      </scripting>
    </system.web.extensions>

    仔细看了一下异常信息,发现,是在System.Web.Mvc.JsonValueProviderFactory 里调用的 JavaScriptSerializer:

    于是查了一下 ,发现 JsonValueProviderFactory 在 System.Web.Mvc.dll 程序集里的:

    反编译 System.Web.Mvc.dll 找到 JsonValueProviderFactory 类:

     
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    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。 

    解决此问题的方法就是 把 javaScriptSerializer.MaxJsonLength = int.MaxValue; (int.MaxValue 值是 2147483647 字节,即2048M)

    自己重写类 JsonValueProviderFactory 命名为 MyJsonValueProviderFactory:

     
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    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 类。

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

     至此,.NET MVC 超出 maxJsonLength 的问题终于解决了!

  • 相关阅读:
    如何修改ls命令列出来的目录颜色
    如何替换vi的配色方案
    grep如何结尾匹配
    机器学习模型如何转换成零依赖代码
    在ubuntu bionic下对基于qemu的arm64进行linux内核5.0.1版本的编译和运行
    分析linux内核中的slub内存管理算法
    windows下如何解决chrome浏览器左下角总提示'Downloading proxy script'的问题
    发现vi出现此错误~/.vim/bundle/YouCompleteMe/third_party/ycmd/ycm_core.so: undefined symbol: clang_getCompletionFixIt
    打开vi后提示The ycmd server SHUT DOWN (restart with :YcmRestartServer)该如何处理
    ubuntu下如何修改时区和时间
  • 原文地址:https://www.cnblogs.com/yanglang/p/8830837.html
Copyright © 2020-2023  润新知