在.Net的MVC开发中,经常会使用到Json对象,于是,系统提供了JsonResult这个对象,其本质是调用.Net系统自带的Json序列化类JavaScriptSerializer对数据对象进行序列化。但是这个系统自带的Json序列化对象方法没有Json.Net好用,于是打算有些时候用Json.Net替代默认的实现。
要实现有时候用Json.Net,有时候用默认实现,那么就要保证系统中两种实现并存。对于Server将对象序列化成Json传给Client很简单,我们只需要建立一个新的ActionResult,我们命名为JsonNetResult,然后在Get时,return这个JsonNetResult即可。JsonNetResult的代码实现为:
<span class="kwrd">namespace MvcJsonNet
{
<span class="kwrd">using System.IO;
<span class="kwrd">using System.Web;
<span class="kwrd">using System.Web.Mvc;
<span class="kwrd">using Newtonsoft.Json;<span class="kwrd">public</span> <span class="kwrd">class</span> JsonNetResult : JsonResult { <span class="kwrd">public</span> JsonNetResult() { Settings = <span class="kwrd">new</span> JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Error }; } <span class="kwrd">public</span> JsonNetResult(<span class="kwrd">object</span> data,JsonRequestBehavior behavior = JsonRequestBehavior.AllowGet,<span class="kwrd">string</span> contentType=<span class="kwrd">null</span>,Encoding contentEncoding=<span class="kwrd">null</span>) { <span class="kwrd">this</span>.Data = data; <span class="kwrd">this</span>.JsonRequestBehavior = behavior; <span class="kwrd">this</span>.ContentEncoding = contentEncoding; <span class="kwrd">this</span>.ContentType = contentType; } <span class="kwrd">public</span> JsonSerializerSettings Settings { get; <span class="kwrd">private</span> set; } <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">void</span> ExecuteResult(ControllerContext context) { <span class="kwrd">if</span> (context == <span class="kwrd">null</span>) <span class="kwrd">throw</span> <span class="kwrd">new</span> ArgumentNullException(<span class="str">"context"</span>); <span class="kwrd">if</span> (<span class="kwrd">this</span>.JsonRequestBehavior == JsonRequestBehavior.DenyGet && <span class="kwrd">string</span>.Equals(context.HttpContext.Request.HttpMethod,<span class="str">"GET"</span>,StringComparison.OrdinalIgnoreCase)) <span class="kwrd">throw</span> <span class="kwrd">new</span> InvalidOperationException(<span class="str">"JSON GET is not allowed"</span>); HttpResponseBase response = context.HttpContext.Response; response.ContentType = <span class="kwrd">string</span>.IsNullOrEmpty(<span class="kwrd">this</span>.ContentType) ? <span class="str">"application/json"</span> : <span class="kwrd">this</span>.ContentType; <span class="kwrd">if</span> (<span class="kwrd">this</span>.ContentEncoding != <span class="kwrd">null</span>) response.ContentEncoding = <span class="kwrd">this</span>.ContentEncoding; <span class="kwrd">if</span> (<span class="kwrd">this</span>.Data == <span class="kwrd">null</span>) <span class="kwrd">return</span>; var scriptSerializer = JsonSerializer.Create(<span class="kwrd">this</span>.Settings); <span class="kwrd">using</span> (var sw = <span class="kwrd">new</span> StringWriter()) { scriptSerializer.Serialize(sw,<span class="kwrd">this</span>.Data); response.Write(sw.ToString()); } } }
}
要返回一个Json.Net序号列后的对象,那么调用方法是:
这是Get方法,但是对于ClientPost一个Json回Server,那么就比较麻烦了,需要修改好几处地方:
1,建立Json.Net的ValueProviderFactory,这个类主要就是用于Json字符串的反序列化。
<span class="kwrd">namespace MvcJsonNet
{
<span class="kwrd">using System.Collections;
<span class="kwrd">using System.Dynamic;
<span class="kwrd">using System.Globalization;
<span class="kwrd">using System.IO;
<span class="kwrd">using System.Web.Mvc;
<span class="kwrd">using System.Web.Script.Serialization;
<span class="kwrd">using Newtonsoft.Json;<span class="kwrd">public</span> <span class="kwrd">class</span> JsonNetValueProviderFactory : ValueProviderFactory { <span class="kwrd">private</span> <span class="kwrd">void</span> AddToBackingStore(Dictionary<<span class="kwrd">string</span>,<span class="kwrd">object</span>> backingStore,<span class="kwrd">string</span> prefix,<span class="kwrd">object</span> <span class="kwrd">value</span>) { IDictionary<<span class="kwrd">string</span>,<span class="kwrd">object</span>> d = <span class="kwrd">value</span> <span class="kwrd">as</span> IDictionary<<span class="kwrd">string</span>,<span class="kwrd">object</span>>; <span class="kwrd">if</span> (d != <span class="kwrd">null</span>) { <span class="kwrd">foreach</span> (KeyValuePair<<span class="kwrd">string</span>,<span class="kwrd">object</span>> entry <span class="kwrd">in</span> d) { AddToBackingStore(backingStore,MakePropertyKey(prefix,entry.Key),entry.Value); } <span class="kwrd">return</span>; } IList l = <span class="kwrd">value</span> <span class="kwrd">as</span> IList; <span class="kwrd">if</span> (l != <span class="kwrd">null</span>) { <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i < l.Count; i++) { AddToBackingStore(backingStore,MakeArrayKey(prefix,i),l[i]); } <span class="kwrd">return</span>; } <span class="rem">// primitive</span> backingStore[prefix] = <span class="kwrd">value</span>; } <span class="kwrd">private</span> <span class="kwrd">object</span> GetDeserializedObject(ControllerContext controllerContext) { <span class="kwrd">if</span> (!controllerContext.HttpContext.Request.ContentType.StartsWith(<span class="str">"application/json"</span>,StringComparison.InvariantCultureIgnoreCase)) { <span class="rem">// not JSON request</span> <span class="kwrd">return</span> <span class="kwrd">null</span>; } StreamReader reader = <span class="kwrd">new</span> StreamReader(controllerContext.HttpContext.Request.InputStream); <span class="kwrd">string</span> bodyText = reader.ReadToEnd(); <span class="kwrd">if</span> (String.IsNullOrEmpty(bodyText)) { <span class="rem">// no JSON data</span> <span class="kwrd">return</span> <span class="kwrd">null</span>; } <span class="rem">//接下来的代码是关键,判断content type,如果是json.net,那么就使用Json.Net的反序列化方法,如果不是,那么就使用系统默认的反序列化方法</span> <span class="kwrd">if</span> (controllerContext.HttpContext.Request.ContentType.StartsWith(<span class="str">"application/json.net"</span>,StringComparison.InvariantCultureIgnoreCase)) { var jsonData = JsonConvert.DeserializeObject<ExpandoObject>(bodyText); <span class="kwrd">return</span> jsonData; } <span class="kwrd">else</span> { JavaScriptSerializer serializer = <span class="kwrd">new</span> JavaScriptSerializer(); <span class="kwrd">object</span> jsonData = serializer.DeserializeObject(bodyText); <span class="kwrd">return</span> jsonData; } } <span class="kwrd">public</span> <span class="kwrd">override</span> IValueProvider GetValueProvider(ControllerContext controllerContext) { <span class="kwrd">if</span> (controllerContext == <span class="kwrd">null</span>) { <span class="kwrd">throw</span> <span class="kwrd">new</span> ArgumentNullException(<span class="str">"controllerContext"</span>); } <span class="kwrd">object</span> jsonData = GetDeserializedObject(controllerContext); <span class="kwrd">if</span> (jsonData == <span class="kwrd">null</span>) { <span class="kwrd">return</span> <span class="kwrd">null</span>; } Dictionary<<span class="kwrd">string</span>,<span class="kwrd">object</span>> backingStore = <span class="kwrd">new</span> Dictionary<<span class="kwrd">string</span>,<span class="kwrd">object</span>>(StringComparer.OrdinalIgnoreCase); AddToBackingStore(backingStore,String.Empty,jsonData); <span class="kwrd">return</span> <span class="kwrd">new</span> DictionaryValueProvider<<span class="kwrd">object</span>>(backingStore,CultureInfo.CurrentCulture); } <span class="kwrd">private</span> <span class="kwrd">string</span> MakeArrayKey(<span class="kwrd">string</span> prefix,<span class="kwrd">int</span> index) { <span class="kwrd">return</span> prefix + <span class="str">"["</span> + index.ToString(CultureInfo.InvariantCulture) + <span class="str">"]"</span>; } <span class="kwrd">private</span> <span class="kwrd">string</span> MakePropertyKey(<span class="kwrd">string</span> prefix,<span class="kwrd">string</span> propertyName) { <span class="kwrd">return</span> (String.IsNullOrEmpty(prefix)) ? propertyName : prefix + <span class="str">"."</span> + propertyName; } }
}