某專案使用[FromPartialBody]在ASP.NET MVC Action接收jQuery送來的物件陣列,初測無誤後進行正式測試,發現只要物件陣列的筆數一多,網頁就會爆炸:
System.InvalidOperationException: The JSON request was too large to be deserialized.
於 System.Web.Mvc.JsonValueProviderFactory.EntryLimitedDictionary.Add(String key, Object value)
於 System.Web.Mvc.JsonValueProviderFactory.AddToBackingStore(EntryLimitedDictionary backingStore, String prefix, Object value)
於 System.Web.Mvc.JsonValueProviderFactory.AddToBackingStore(EntryLimitedDictionary backingStore, String prefix, Object value)
於 System.Web.Mvc.JsonValueProviderFactory.AddToBackingStore(EntryLimitedDictionary backingStore, String prefix, Object value)
於 System.Web.Mvc.JsonValueProviderFactory.AddToBackingStore(EntryLimitedDictionary backingStore, String prefix, Object value)
於 System.Web.Mvc.JsonValueProviderFactory.GetValueProvider(ControllerContext controllerContext)
於 System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext)
於 System.Web.Mvc.ControllerBase.get_ValueProvider()
於 System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
於 System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
於 System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass21.<BeginInvokeAction>b__19(AsyncCallback asyncCallback, Object asyncState)
爬文很快找到解決方案,web.config裡有個aspnet:MaxJsonDeserializerMembers參數,預設值為1000,超過上限就會出現前述錯誤。留下一個疑點,測試資料筆數不可能超過400筆,MaxJsonDeserializerMembers上限1000的單位為何?
用F12開發者工具檢查Request內容,果然資料只有366筆。
依MSDN文件的MaxJsonDeserializerMembers說明:Specifies the limit of the maximum number of items that can be present in any dictionary deserialized by the JavaScriptSerializer type. 推測每組 PropName: "PropValue" 就算一個Item。換言之,data陣列有366個元素,每個各有CostCenter、JobType、UserId、Weight四個屬性,366x4 + 2(approve及wuid)=1466,突破1000關卡。為證實猜想,刻意將aspnet:MaxJsonDeserializerMembers調為1465以及1466,果真得到1465失敗,1466成功的結果,驗證前面的Member個數定義正確。有了這個基礎,我們就能精準估算MaxJsonDeserializerMembers該設多大。
咦?為什麼不設一個宇宙無敵大的上限就好,要傷這種腦筋?依老骨頭的直覺,預設值偏低必有玄機,恣意加大絕非上策。微軟的這篇KB說明始末:MaxJsonDeserializerMembers是在MS11-100安全更新時刻意調小的,目的在防止有人藉由傳送超大JSON癱瘓ASP.NET網站達到DoS攻擊的目的。也許是說,MaxJsonDeserializerMembers被調得愈大,網站被攻擊癱瘓的風險也愈高,修改設定宜謹慎拿捏。