今日碰到了這么一個(gè)異常,異常信息如下:
Type : System.InvalidOperationException, mscorlib, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089
Message : 使用 JSON JavaScriptSerializer 進(jìn)行序列化或反序列化時(shí)出錯(cuò)。字符串的長(zhǎng)度超過(guò)了為 maxJsonLength 屬性設(shè)置的值。
Source : System.Web.Extensions
Help link :
Data : System.Collections.ListDictionaryInternal
TargetSite : Void Serialize(System.Object, System.Text.StringBuilder,
SerializationFormat)
Stack Trace : 在
System.Web.Script.Serialization.JavaScriptSerializer.Serialize(Object obj,
StringBuilder output, SerializationFormat serializationFormat)
在 System.Web.Script.Serialization.JavaScriptSerializer.Serialize(Object
obj, SerializationFormat serializationFormat)
在 System.Web.Script.Serialization.JavaScriptSerializer.Serialize(Object
這個(gè)異常是在執(zhí)行MVC中的JsonResult的時(shí)拋出的,根據(jù)異常的Message得知是序列化的字符串超出了maxJsonLength的限制。并得知這個(gè)屬性是由JavaScriptSerializer提供的,因?yàn)镸VC內(nèi)置的JsonResult是用JavaScriptSerializer進(jìn)行序列化的。在網(wǎng)上快速搜索了一下,碰到這個(gè)問(wèn)題的童鞋不少,大部分推薦的解決的方法都是在web.config中加入以下配置,設(shè)置maxJsonLength的長(zhǎng)度即可。
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="20971520"/>
</webServices>
</scripting>
</system.web.extensions>
在自動(dòng)提示下,很順暢的加上了幾行代碼,以為這是個(gè)簡(jiǎn)潔的解決方案,但是運(yùn)行網(wǎng)站之后報(bào)以下錯(cuò)誤:
分析器錯(cuò)誤消息: 無(wú)法識(shí)別的配置節(jié) system.web.extensions。
這似乎又是碰到了一家人不認(rèn)識(shí)的情況,既然無(wú)法識(shí)別為什么能帶智能感知的方式輸出,而且是已system.web開(kāi)頭的,按道理不會(huì)識(shí)別不出的。以為是拼寫(xiě)錯(cuò)誤,經(jīng)過(guò)進(jìn)一步搜索之后,原來(lái)是缺乏了聲明,加上對(duì)節(jié)點(diǎn)的聲明即可(很大一串的內(nèi)容)。
<sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
<sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="Everywhere"/>
<section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
<section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
<section name="roleService" type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
</sectionGroup>
</sectionGroup>
</sectionGroup>
加入了聲明之后,運(yùn)行正常,但是問(wèn)題依舊還在,而且不管maxJsonLength設(shè)置成多大都無(wú)效,就算改成1個(gè)字符,居然還能跑起來(lái)。碰到這個(gè)問(wèn)題只能進(jìn)一步的搜索。在這篇文章中找到了原委http://weblogs.asp.net/rashid/archive/2009/03/23/submitting-my-first-bug-after-asp-net-mvc-1-0-rtm-release.aspx。
原來(lái)MVC框架內(nèi)置的JsonResult代碼中,在使用JavaScriptSerializer時(shí),都是采用的默認(rèn)值,沒(méi)有從maxJsonLength讀取值,即忽略了這個(gè)配置。要想使用配置中的值,只能自定義一個(gè)JsonResult,重寫(xiě)原JsonResult的ExecuteResult方法,于是定義一個(gè)ConfigurableJsonResult,代碼如下:
ConfigurableJsonResult
1 public class ConfigurableJsonResult : JsonResult
2 {
3 public override void ExecuteResult(ControllerContext context)
4 {
5 if (context == null)
6 {
7 throw new ArgumentNullException("context");
8 }
9 if (JsonRequestBehavior == JsonRequestBehavior.DenyGet &&
10 String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
11 {
12 throw new InvalidOperationException("This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.");
13 }
14
15 HttpResponseBase response = context.HttpContext.Response;
16
17 if (!String.IsNullOrEmpty(ContentType))
18 {
19 response.ContentType = ContentType;
20 }
21 else
22 {
23 response.ContentType = "application/json";
24 }
25 if (ContentEncoding != null)
26 {
27 response.ContentEncoding = ContentEncoding;
28 }
29 if (Data != null)
30 {
31 JavaScriptSerializer serializer = new JavaScriptSerializer();
32
33 ScriptingJsonSerializationSection section = ConfigurationManager.GetSection("system.web.extensions/scripting/webServices/jsonSerialization") as ScriptingJsonSerializationSection;
34
35 if (section != null)
36 {
37 serializer.MaxJsonLength = section.MaxJsonLength;
38 serializer.RecursionLimit = section.RecursionLimit;
39 }
40
41 response.Write(serializer.Serialize(Data));
42 }
43 }
44 }
關(guān)鍵在紅色標(biāo)記的代碼,讀取配置的值。JavaScriptSerializer還有其他屬性可配置,沒(méi)有列出與實(shí)現(xiàn),暫時(shí)夠用。
這樣在返回長(zhǎng)字符內(nèi)容的json結(jié)果時(shí),直接替換原JsonResult即可,同時(shí)也兼顧了可配置的靈活性。