接續「ASP.NET MVC + JSON 自定義JsonResult 1」的內容,
上一篇文章的最後有說,Json.NET所提供的 JsonNetResult類別並不是很適合拿來使用,
而在「使用Entity Framework 將物件轉為JSON時遇到循環參考錯誤 3」裡面,我們也建立了兩個JavaScriptConverter類別,
所以我們就自己來建立一個自己定義的JsonResult,並且使用之前所建立EFJavaScriptSerializer,
這個 EFJavaScriptSerializer 可以分別依據狀況使用 EFSimpleJavaScriptConverter 或 EFJavaScriptConverter…
廢話不多說,直接來看做好的 CustomJsonResult 類別:
using System;
using System.Text;
using System.Web;
using System.Web.Mvc;
namespace Test.Helper
{public class CustomJsonResult : JsonResult{public new Encoding ContentEncoding { get; set; }public int? MaxDepth { get; set; }public CustomJsonResult()
{JsonRequestBehavior = JsonRequestBehavior.DenyGet;}public override void ExecuteResult(ControllerContext context){if (context == null){throw new ArgumentNullException("context");}HttpResponseBase response = context.HttpContext.Response;response.ContentType = !String.IsNullOrEmpty(ContentType)? ContentType: "application/json";
response.ContentEncoding = this.ContentEncoding == null? System.Text.Encoding.UTF8: this.ContentEncoding;
if (Data != null){EFJavaScriptSerializer serializer = !this.MaxDepth.HasValue
? new EFJavaScriptSerializer()
: new EFJavaScriptSerializer(this.MaxDepth.Value);response.Write(serializer.Serialize(Data));}}}}
這個類別繼承 JsonResult,這個 CustomJsonResult 比原本的JsonResult 還多了一個 MaxDeprth 屬性,
這是可以在做序列化時,使用 EFJavaScriptConverter 去轉換資料到多少的深度,
預設的Content-Type為「application/json」
預設的Encoding為「System.Text.Encoding.UTF8」
最後建立的EFJavaScriptSerializer則會根據MaxDepth的數值來決定是要用哪一個 JavaScriptConverter。
EFJavaScriptSerializer類別:
當沒有指定MaxDepth數值時,會使用EFSimpleJavaScriptConverter來做序列化,只會轉換物件本身的欄位,不包含關連資料。
當有指定MaxDepth時,則使用 EFJavaScriptConverter來做序列化,且依據深度來包含轉換多少深度的關連資料。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Script.Serialization;
namespace Test.Helper
{
public class EFJavaScriptSerializer : JavaScriptSerializer
{
public EFJavaScriptSerializer()
{
RegisterConverters(new List<JavaScriptConverter> { new EFSimpleJavaScriptConverter() });
}
public EFJavaScriptSerializer(int maxDepth = 1, EFJavaScriptConverter parent = null)
{
if (maxDepth < 1)
{
RegisterConverters(new List<JavaScriptConverter> { new EFSimpleJavaScriptConverter() });
}
else
{
RegisterConverters(new List<JavaScriptConverter> { new EFJavaScriptConverter(maxDepth, parent) });
}
}
}
}
使用情境一:
序列化一個從EF取出的Product物件,不指定深度,所以這個只會序列化Product物件自己的欄位資料。
public JsonResult Product(int? id){if (!id.HasValue)
{Dictionary<string, string> jo = new Dictionary<string, string>();jo.Add("Msg", "請輸入產品ID編號.");return Json(jo);
}else
{ProductService service = new ProductService();
var product = service.Single(id.Value);return new CustomJsonResult{Data = product,JsonRequestBehavior = JsonRequestBehavior.AllowGet};}}
執行結果:
使用情境二:
序列化CategoryID為1的Product集合,不指定深度。
public JsonResult Product(int? id){if (!id.HasValue)
{Dictionary<string, string> jo = new Dictionary<string, string>();jo.Add("Msg", "請輸入產品ID編號.");return Json(jo);
}else
{ProductService service = new ProductService();
var products = service.FindBy(id.Value);return new CustomJsonResult{Data = products,JsonRequestBehavior = JsonRequestBehavior.AllowGet};}}
執行結果:
使用情境三:
序列化一個從EF取出的Product物件,指定深度為1,所以會序列化Product物件自己的欄位資料以及關連的物件。
public JsonResult Product(int? id){if (!id.HasValue)
{Dictionary<string, string> jo = new Dictionary<string, string>();jo.Add("Msg", "請輸入產品ID編號.");return Json(jo);
}else
{ProductService service = new ProductService();
var product = service.Single(id.Value);return new CustomJsonResult{Data = product,MaxDepth = 1,JsonRequestBehavior = JsonRequestBehavior.AllowGet};}}
執行結果:
使用情境四:
序列化CategoryID為1的Product集合,指定深度為1。
public JsonResult Product(int? id){if (!id.HasValue)
{Dictionary<string, string> jo = new Dictionary<string, string>();jo.Add("Msg", "請輸入產品ID編號.");return Json(jo);
}else
{ProductService service = new ProductService();
var products = service.FindBy(id.Value);return new CustomJsonResult{Data = products,MaxDepth = 1,JsonRequestBehavior = JsonRequestBehavior.AllowGet};}}
執行結果:
在Controller中使用JsonResult的Action,在序列化物件的時候就可以使用CustomJsonResult類別。
如果說,每次使用JsonResult的Action於最後的回傳不想用 new CustomJsonResult{ … } 的方式,
可以另外建立一個BaseController類別,然後在這個BaseController類別中去建立CustomJson()方法
BaseController類別:
using System.Web.Mvc;
using Test.Helper;
namespace Test.Web
{public class BaseController : Controller{protected internal JsonResult CustomJson(object data){return new CustomJsonResult { Data = data };}protected internal JsonResult CustomJson(object data, JsonRequestBehavior jsonRequestBehavior = JsonRequestBehavior.DenyGet){return new CustomJsonResult { Data = data, JsonRequestBehavior = jsonRequestBehavior };}protected internal JsonResult CustomJson(object data, int maxDepth = 1){return new CustomJsonResult { Data = data, MaxDepth = maxDepth };}protected internal JsonResult CustomJson(object data, int maxDepth = 1, JsonRequestBehavior jsonRequestBehavior = JsonRequestBehavior.DenyGet){return new CustomJsonResult { Data = data, MaxDepth = maxDepth, JsonRequestBehavior = jsonRequestBehavior };}}}
而修改後的Action:
沒有指定深度
public JsonResult Product(int? id){if (!id.HasValue)
{Dictionary<string, string> jo = new Dictionary<string, string>();jo.Add("Msg", "請輸入產品ID編號.");return Json(jo);
}else
{ProductService service = new ProductService();
var products = service.FindBy(id.Value);//return new CustomJsonResult
//{
// Data = products,
// JsonRequestBehavior = JsonRequestBehavior.AllowGet
//};
return CustomJson(products, JsonRequestBehavior.AllowGet);
}}
指定深度
public JsonResult Product(int? id){if (!id.HasValue)
{Dictionary<string, string> jo = new Dictionary<string, string>();jo.Add("Msg", "請輸入產品ID編號.");return Json(jo);
}else
{ProductService service = new ProductService();
var products = service.FindBy(id.Value);//return new CustomJsonResult
//{
// Data = products,
// MaxDepth = 1,
// JsonRequestBehavior = JsonRequestBehavior.AllowGet
//};
return CustomJson(products, 1, JsonRequestBehavior.AllowGet);
}}
這樣在return時就可以使用CustomJson(),不必使用 return new CustomJsonResult{ … }。
延伸閱讀:
ASP.NET MVC + JSON 自定義JsonResult 1
使用Entity Framework 將物件轉為JSON時遇到循環參考錯誤 3
參考連結:
Json.NET - ASP.NET MVC and Json.NET:JsonNetResult
Stackoverflow - Using JSON.net as default JSON serializer in ASP.NET MVC 3 - Is it possible?
Stackoverflow - Change Default JSON Serializer Used In ASP MVC3
以上
CustomJson寫成Controller的擴充方法也不錯
回覆刪除