xiaoafei1991

导航

超高性能的json序列化之MVC中使用Json.Net

先不废话,直接上代码

Asp.net MVC自带Json序列化

 1 /// <summary>
 2 /// 加载组件列表
 3 /// </summary>
 4 /// <param name="departmentId">作业部/厂</param>
 5 /// <param name="unitId">组件Id</param>
 6 /// <param name="tag">标签号</param>
 7 /// <param name="pageIndex">当前页码</param>
 8 /// <param name="pageSize">每页条数</param>
 9 /// <returns>返回组件json数据</returns>
10 public JsonResult ListCom(long departmentId, IEnumberable<long> unitIds, string tag, int pageIndex, int pageSize)
11 {
12     var dataEntity = LdarService.ListCom(unitIds, tag, pageIndex + 1, pageSize);
13     var dataModel = new Page<LdComModel> {Total = dataEntity.Total};
14     var data =
15         dataModel.DataList =
16             dataEntity.DataList.Select(model => Builder.Builder.Convert<LdComModel>(new object[] {model}));//Entity转ViewModel
17     dataModel.DataList = data;
18     return Json(new {
19             msg = CommonModelBuilder.BuildQuerySuccessMessage("组件信息维护", (int) dataModel.Total),
20             data = dataModel.DataList,
21             total = dataModel.Total
22         });
23 }
显示到前台界面

接收到的报文中有很多导航属性,前台并不需要这些属性.

LdComModel类中关联了很多外表,也就是导航属性,导航也被序列化,这样不科学,会将所有属性包括导航属性都序列化,还可能会造成循环引用,导致报错。
我只想序列需要的字段,这时可以手写一个匿名类
1 var data=new {
2      model.AreaName,
3      model.AreaId,
4      ......                  
5 };

这么写字段少还好,字段多就很不爽吧。

这时我们可以用Json.Net序列化,首先引用newtonsoft.json.dll,使用nuget引用比较方便。在不想序列化的属性上打上[JsonIgnore]特性,序列化就会被忽略。

LdComModel类中的部分代码
 1 /// <summary>
 2 /// 分区
 3 /// </summary>
 4 [JsonIgnore]
 5 public LdAreaModel LdAreaModel { get; set; }
 6 
 7 /// <summary>
 8 /// 区域名称
 9 /// </summary>
10 public string AreaName
11 {
12     get
13     {
14         return LdAreaModel.LdarAreaName;
15     }
16 }

 

使用JsonNet序列化

 1 /// <summary>
 2 /// 加载组件列表
 3 /// </summary>
 4 /// <param name="departmentId">作业部/厂</param>
 5 /// <param name="unitId">组件Id</param>
 6 /// <param name="tag">标签号</param>
 7 /// <param name="pageIndex">当前页码</param>
 8 /// <param name="pageSize">每页条数</param>
 9 /// <returns>返回组件json数据</returns>
10 public JsonResult ListCom(long departmentId, IEnumberable<long> unitIds, string tag, int pageIndex, int pageSize)
11 {
12     var dataEntity = LdarService.ListCom(unitIds, tag, pageIndex + 1, pageSize);
13     var dataModel = new Page<LdComModel> {Total = dataEntity.Total};
14     var data =
15         dataModel.DataList =
16             dataEntity.DataList.Select(model => Builder.Builder.Convert<LdComModel>(new object[] {model}));//Entity转ViewModel
17     dataModel.DataList = data;
18     var result = new JsonNetResult()
19         {
20             Data = new
21             {
22                 msg = CommonModelBuilder.BuildQuerySuccessMessage("组件信息维护", (int) dataModel.Total),
23                 data = dataModel.DataList,
24                 total = dataModel.Total
25             }
26         };
27         return result;
28 }

这时返回到前台的json中没有多余的导航属性.

导航属性没有被序列化,速度也快了很多。

这样写,虽然可以实现功能,很每次都要new一个JsonNetResult对象,写起来很是不爽,能不能给Controller写个扩展方法,像Json(...)一样直接写JsonNet(...)?

Controller中Json(...)方法的部分源码

 1     /// <summary>
 2     /// 创建一个将指定对象序列化为 JavaScript 对象表示法 (JSON) 的 <see cref="T:System.Web.Mvc.JsonResult"/> 对象。
 3     /// </summary>
 4     /// 
 5     /// <returns>
 6     /// 将指定对象序列化为 JSON 格式的 JSON 结果对象。在执行此方法所准备的结果对象时,ASP.NET MVC 框架会将该对象写入响应。
 7     /// </returns>
 8     /// <param name="data">要序列化的 JavaScript 对象图。</param>
 9     protected internal JsonResult Json(object data)
10     {
11       return this.Json(data, (string) null, (Encoding) null, JsonRequestBehavior.DenyGet);
12     }
13 
14 // <summary>
15     /// 创建 <see cref="T:System.Web.Mvc.JsonResult"/> 对象,该对象使用内容类型、内容编码和 JSON 请求行为将指定对象序列化为 JavaScript 对象表示法 (JSON) 格式。
16     /// </summary>
17     /// 
18     /// <returns>
19     /// 将指定对象序列化为 JSON 格式的结果对象。
20     /// </returns>
21     /// <param name="data">要序列化的 JavaScript 对象图。</param><param name="contentType">内容类型(MIME 类型)。</param><param name="contentEncoding">内容编码。</param><param name="behavior">JSON 请求行为</param>
22     protected internal virtual JsonResult Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior)
23     {
24       return new JsonResult()
25       {
26         Data = data,
27         ContentType = contentType,
28         ContentEncoding = contentEncoding,
29         JsonRequestBehavior = behavior
30       };
31     }

我们可以仿照Controller中的源码,自己给Controller写个扩展方法JsonNet(...)

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Web;
  6 
  7 namespace System.Web.Mvc
  8 {
  9     public static class ControllerExt
 10     {
 11         /// <summary>
 12         /// 创建一个将指定对象序列化为 JavaScript 对象表示法 (JSON) 的 <see cref="T:System.Web.Mvc.JsonNetResult"/> 对象。
 13         /// </summary>
 14         /// 
 15         /// <returns>
 16         /// 将指定对象序列化为 JSON 格式的 JSON 结果对象。在执行此方法所准备的结果对象时,ASP.NET MVC 框架会将该对象写入响应。
 17         /// </returns>
 18         /// <param name="controller">控件器</param>
 19         /// <param name="data">要序列化的 JavaScript 对象图。</param>
 20         public static JsonNetResult JsonNet(this Controller controller, object data)
 21         {
 22             return JsonNet(data, (string) null, (Encoding) null, JsonRequestBehavior.DenyGet);
 23         }
 24 
 25         /// <summary>
 26         /// 创建一个将指定对象序列化为 JavaScript 对象表示法 (JSON) 格式的 <see cref="T:System.Web.Mvc.JsonNetResult"/> 对象。
 27         /// </summary>
 28         /// 
 29         /// <returns>
 30         /// 将指定对象序列化为 JSON 格式的 JSON 结果对象。
 31         /// </returns>
 32         /// <param name="controller">控件器</param>
 33         /// <param name="data">要序列化的 JavaScript 对象图。</param>
 34         /// <param name="contentType">内容类型(MIME 类型)。</param>
 35         public static JsonNetResult JsonNet(this Controller controller, object data, string contentType)
 36         {
 37             return JsonNet(data, contentType, (Encoding) null, JsonRequestBehavior.DenyGet);
 38         }
 39 
 40         /// <summary>
 41         /// 创建一个将指定对象序列化为 JavaScript 对象表示法 (JSON) 格式的 <see cref="T:System.Web.Mvc.JsonNetResult"/> 对象。
 42         /// </summary>
 43         /// 
 44         /// <returns>
 45         /// 将指定对象序列化为 JSON 格式的 JSON 结果对象。
 46         /// </returns>
 47         /// <param name="controller">控件器</param>
 48         /// <param name="data">要序列化的 JavaScript 对象图。</param>
 49         /// <param name="contentType">内容类型(MIME 类型)。</param>
 50         /// <param name="contentEncoding">内容编码。</param>
 51         public static JsonNetResult JsonNet(this Controller controller, object data, string contentType,
 52             Encoding contentEncoding)
 53         {
 54             return JsonNet(data, contentType, contentEncoding, JsonRequestBehavior.DenyGet);
 55         }
 56 
 57         /// <summary>
 58         /// 创建 <see cref="T:System.Web.Mvc.JsonNetResult"/> 对象,该对象使用指定 JSON 请求行为将指定对象序列化为 JavaScript 对象表示法 (JSON) 格式。
 59         /// </summary>
 60         /// 
 61         /// <returns>
 62         /// 将指定对象序列化为 JSON 格式的结果对象。
 63         /// </returns>
 64         /// <param name="controller">控件器</param>
 65         /// <param name="data">要序列化的 JavaScript 对象图。</param>
 66         /// <param name="behavior">JSON 请求行为。</param>
 67         public static JsonNetResult JsonNet(this Controller controller, object data, JsonRequestBehavior behavior)
 68         {
 69             return JsonNet(data, (string) null, (Encoding) null, behavior);
 70         }
 71 
 72         /// <summary>
 73         /// 创建 <see cref="T:System.Web.Mvc.JsonNetResult"/> 对象,该对象使用指定内容类型和 JSON 请求行为将指定对象序列化为 JavaScript 对象表示法 (JSON) 格式。
 74         /// </summary>
 75         /// 
 76         /// <returns>
 77         /// 将指定对象序列化为 JSON 格式的结果对象。
 78         /// </returns>
 79         /// <param name="controller">控件器</param>
 80         /// <param name="data">要序列化的 JavaScript 对象图。</param>
 81         /// <param name="contentType">内容类型(MIME 类型)。</param>
 82         /// <param name="behavior">JSON 请求行为</param>
 83         public static JsonNetResult JsonNet(this Controller controller, object data, string contentType,
 84             JsonRequestBehavior behavior)
 85         {
 86             return JsonNet(data, contentType, (Encoding) null, behavior);
 87         }
 88 
 89         /// <summary>
 90         /// 创建 <see cref="T:System.Web.Mvc.JsonNetResult"/> 对象,该对象使用内容类型、内容编码和 JSON 请求行为将指定对象序列化为 JavaScript 对象表示法 (JSON) 格式。
 91         /// </summary>
 92         /// 
 93         /// <returns>
 94         /// 将指定对象序列化为 JSON 格式的结果对象。
 95         /// </returns>
 96         /// <param name="controller">控件器</param>
 97         /// <param name="data">要序列化的 JavaScript 对象图。</param>
 98         /// <param name="contentType">内容类型(MIME 类型)。</param>
 99         /// <param name="contentEncoding">内容编码。</param><param name="behavior">JSON 请求行为</param>
100         public static JsonNetResult JsonNet(this Controller controller, object data, string contentType,
101             Encoding contentEncoding, JsonRequestBehavior behavior)
102         {
103             return JsonNet(data, contentType, contentEncoding, behavior);
104         }
105 
106         /// <summary>
107         /// 创建 <see cref="T:System.Web.Mvc.JsonNetResult"/> 对象,该对象使用内容类型、内容编码和 JSON 请求行为将指定对象序列化为 JavaScript 对象表示法 (JSON) 格式。
108         /// </summary>
109         /// <param name="data">要序列化的 JavaScript 对象图。</param>
110         /// <param name="contentType">内容类型(MIME 类型)。</param>
111         /// <param name="contentEncoding">内容编码。</param>
112         /// <param name="behavior"></param>
113         /// <returns>JSON 请求行为</returns>
114         private static JsonNetResult JsonNet(object data, string contentType, Encoding contentEncoding,
115             JsonRequestBehavior behavior)
116         {
117             return new JsonNetResult()
118             {
119                 Data = data,
120                 ContentType = contentType,
121                 ContentEncoding = contentEncoding,
122                 JsonRequestBehavior = behavior
123             };
124         }
125 
126     }
127 }
Controller扩展方法

 

写个JsonNetResult类,继承自JsonResult,重写ExecuteResult()方法,内部使用JsonNet来序列化。

 1 using System.Text;
 2 using Newtonsoft.Json;
 3 
 4 namespace System.Web.Mvc
 5 {
 6     public class JsonNetResult : JsonResult
 7     {
 8         public Encoding ContentEncoding { get; set; }
 9         public string ContentType { get; set; }
10         public object Data { get; set; }
11 
12         public JsonSerializerSettings SerializerSettings { get; set; }
13         public Formatting Formatting { get; set; }
14 
15         public JsonNetResult()
16         {
17             SerializerSettings = new JsonSerializerSettings();
18         }
19 
20         public override void ExecuteResult(ControllerContext context)
21         {
22             if (context == null)
23                 throw new ArgumentNullException("context");
24 
25             HttpResponseBase response = context.HttpContext.Response;
26 
27             response.ContentType = !string.IsNullOrEmpty(ContentType)
28               ? ContentType
29               : "application/json";
30 
31             if (ContentEncoding != null)
32                 response.ContentEncoding = ContentEncoding;
33 
34             if (Data != null)
35             {
36                 var writer = new JsonTextWriter(response.Output) { Formatting = Formatting };
37 
38                 JsonSerializer serializer = JsonSerializer.Create(SerializerSettings);
39                 serializer.Serialize(writer, Data);
40 
41                 writer.Flush();
42             }
43         }
44     }
45 }
JsonNetResult

 

封装后的JsonNet序列化

 1 /// <summary>
 2 /// 加载组件列表
 3 /// </summary>
 4 /// <param name="departmentId">作业部/厂</param>
 5 /// <param name="unitId">组件Id</param>
 6 /// <param name="tag">标签号</param>
 7 /// <param name="pageIndex">当前页码</param>
 8 /// <param name="pageSize">每页条数</param>
 9 /// <returns>返回组件json数据</returns>
10 public JsonNetResult ListCom(long departmentId, IEnumberable<long> unitIds, string tag, int pageIndex, int pageSize)
11 {
12     var dataEntity = LdarService.ListCom(listUnitId, tag, pageIndex + 1, pageSize);
13     var dataModel = new Page<LdComModel> {Total = dataEntity.Total};
14     var data =
15         dataModel.DataList =
16             dataEntity.DataList.Select(model => Builder.Builder.Convert<LdComModel>(new object[] {model}));//Entity转ViewModel
17     dataModel.DataList = data;
18     return this.JsonNet(new
19     {
20         msg = CommonModelBuilder.BuildQuerySuccessMessage("组件信息维护", (int) dataModel.Total),
21         data = dataModel.DataList,
22         total = dataModel.Total
23     });
24 }

 这样调用起来跟自带的Json(...)一样,非常方便。

由于时间关系,博客就先写到这里。不足及错误之处,敬请批评指正。

posted on 2015-01-23 09:14  xiaoafei1991  阅读(5663)  评论(27编辑  收藏  举报