.NET MVC JSON JavaScriptSerializer 字元串的長度超過 maxJsonLength 值問題的解決

来源:https://www.cnblogs.com/anjou/archive/2018/04/13/8819653.html
-Advertisement-
Play Games

.NET MVC JSON JavaScriptSerializer 字元串的長度超過 maxJsonLength 值問題的解決 ...


[ArgumentException: 使用 JSON JavaScriptSerializer 序列化或還原序列化期間發生錯誤。字元串的長度超過在 maxJsonLength 屬性上設定的值。
參數名稱: input]
   System.Web.Script.Serialization.JavaScriptSerializer.Deserialize(JavaScriptSerializer serializer, String input, Type type, Int32 depthLimit) +168
   System.Web.Mvc.JsonValueProviderFactory.GetDeserializedObject(ControllerContext controllerContext) +213
   System.Web.Mvc.JsonValueProviderFactory.GetValueProvider(ControllerContext controllerContext) +16
   System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext) +69
   System.Web.Mvc.ControllerBase.get_ValueProvider() +30  

由於前端 Post 到 Action 的參數太大,超過了2M,還沒進入後臺的 Action 方法就報錯了。這個問題困擾了很久,一直未解決。網上找了幾個方法都無效。

在 web.config 中加入這些,沒有作用:

<appSettings>
  <add key="aspnet:MaxJsonDeserializerMembers" value="2147483647" />
  <add key="aspnet:UpdatePanelMaxScriptLength" value="2147483647" />
</appSettings>

在 web.config 中加入這些,也沒有作用:

<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 類:

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:

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 類。

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

 至此,.NET MVC 超出 maxJsonLength 的問題終於解決了!

  

  

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • sqlalchemy中使用query查詢,而flask-sqlalchemy中使用basequery查詢,他們是子類與父類的關係 假設 page_index=1,page_size=10;所有分頁查詢不可以再跟first(),all()等 1.用offset()設置索引偏移量,limit()限制取出 ...
  • web api與webservice以及wcf的區別? Web Service 1、它是基於SOAP協議的,數據格式是XML 2、只支持HTTP協議 3、它不是開源的,但可以被任意一個瞭解XML的人使用 4、它只能部署在IIS上 WCF 1、這個也是基於SOAP的,數據格式是XML 2、這個是Web ...
  • 概述 UWP Community Toolkit Extensions 中有一個為 WebView 提供的擴展 - WebViewExtensions,本篇我們結合代碼詳細講解 WebView Extensions 的實現。 WebView Extensions 允許使用附加屬性,在 XAML 中指 ...
  • C#情懷與未來,怨天尤人還是抓住機會,能否跟上dnc新時代浪潮? 經常看到有.NET圈子在討論是否應該轉其它語言 C#情懷是一方面,如果覺得C#未來沒前途,光靠情懷是撐不住的, 建議對C#未來沒信心的朋友,轉go、rust、py、TS、JS、java …… 常常看到有人抱怨.NET,抱怨好幾年了,卻 ...
  • IoC框架最本質的東西:反射或者EMIT來實例化對象。然後我們可以加上緩存,或者一些策略來控制對象的生命周期,比如是否是單例對象還是每次都生成一個新的對象。 之前對DI註入與控制器擴展竟然用依賴性解析器來實現,兩個方面深感疑惑,由於越學越不懂,越學越頭暈,因此就暫且放下了,接著學習,誰知道今天寫程式 ...
  • 游戲規則說明: 由系統生成一個隨機數,玩家有三次猜數字的機會,如果在三次內猜出數字反饋玩家猜對了,否則Game Over! 代碼設計說明: 1.首先設計一個簡易的歡迎界面,並提示玩家是否開始游戲; 2.由系統自動生成一個隨機數; 3.由玩家輸入一個數值與系統生成隨機數進行比較,判斷是否相同,如果相同 ...
  • 在 Web 開發中,img 標簽用來呈現圖片,而且一般來說,瀏覽器是會對這些圖片進行緩存的。 比如訪問百度,我們可以發現,圖片、腳本這種都是從緩存(記憶體緩存/磁碟緩存)中載入的,而不是再去訪問一次百度的伺服器,這樣一方面改善了響應速度,另一方面也減輕了服務端的壓力。 但是,對於 WPF 和 UWP ...
  • Hello Everybody,在Smobiler 4.4中,也為大家帶來了新增功能和插件(重點,敲黑板)。 新增功能: 1, 企業認證用戶可設置路由(即客戶端可根據不同的IP地址訪問不同的伺服器組)。 2, TreeView控制項增加ImageType屬性,增加對Image支持。 3, 微信組件新增 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...