這算是個練習的題目,原本覺得應該是個簡單的應用,沒想到實做下去遇到了幾個進階的操作,還蠻有趣的,用的是 ASP.NET Core WebAPI,但如果要用在 ASP.NET WebAPI 專案裡也是可以的,程式的部分並不會有多大的差異。寫程式的過程中還發想出不少的延伸應用情境,所以之後會有幾篇文章跟這篇的內容有所關連。
這篇文章會提到的內容:GZipStream, JsonConvert, AutoMapper
這算是個練習的題目,原本覺得應該是個簡單的應用,沒想到實做下去遇到了幾個進階的操作,還蠻有趣的,用的是 ASP.NET Core WebAPI,但如果要用在 ASP.NET WebAPI 專案裡也是可以的,程式的部分並不會有多大的差異。寫程式的過程中還發想出不少的延伸應用情境,所以之後會有幾篇文章跟這篇的內容有所關連。
這篇文章會提到的內容:GZipStream, JsonConvert, AutoMapper
之前我們介紹了 LINQ to JavaScript (JSLINQ)的基本使用方式,而我們所下載的JSLINQ是2009年所發佈的版本,
在JSLINQ的Codeplex的網站上作者所簽入Source Code離最近一次的日期是 2010-11-13,
所以我們就來使用這Source Code裡最新版本的函式庫,新版本的函式庫中有新增了幾個function,
而我們就來看看這些新的function以及進行幾個進階操作。
在上一篇「前端處理JSON資料 - 轉為陣列以及簡單篩選」說明了如何使用 $.grep() 方法在前端程式中去篩選陣列中的資料,
但是如果要處理的篩選條件是比較複雜時,使用 $.grep() 依然是可行,但總會任人覺得不是那麼方便,
尤其是寫 C# 的開發者在 .NET Framework 3.5 之後對於集合資料的操作已經熟悉並且習慣了 LINQ 語法,
而在前端程式中卻沒有這樣方便的處理方式,在處理集合資料時就會覺得綁手綁腳的,
其實這情形早已經有人做了一個解決方案,「LINQ to JavaScript」( 簡稱為 JSLINQ ),
在2009年的時候在MSDN學習園地的CodePlex教學中就有對這個函式庫做介紹「LINQ to JavaScript: 在 JavsScript 也可以用 LINQ」
接下來就來說明一下使用的方式。
寫ASP.NET MVC的時候,前端與後端的資料處理上常常都會使用到JSON格式的資料,
頁面上的資料呈現與處理都可以直接使用前端程式來執行,而後端就只需要去做產出資料與接收資料的工作,
而前端程式中要去處理JSON資料時,我比較常用的就是把它轉為物件陣列然後再做進階的處理,
以下就簡單記錄一下這些處理的操作方式。
基本上計算日期的差距可以在後端的程式裡或是在資料庫中就可以解決,
但有些時候資料只會在前端出現而未後送到Server Side,或是說不想增加資料庫或是Server Side的負載,
所以就會將這種單純的顯示日期時間差距的計算工作給放到前端去做,
這樣做其實也是有好處的,好處就是讓Client Side去做這類瑣碎的計算,
因為不牽涉到太複雜的邏輯計算,也算是分擔後端的壓力。
所以接下來就會介紹三種方式來達成在Client Side去計算日期時間差距的功能。
上一篇「ASP.NET MVC, JSON資料的日期轉換與格式化 1」說明了後端序列化的JSON日期資料要如何轉換以及格式化,
然而我們在後端所用的序列化JSON是直接使用ASP.NET MVC的預設內部方法,也就是用JavascriptSerializer來做序列化,
而之前有好幾篇文章也有說明到各種的在後端序列化的方式,
所以這一篇我們就來看看各種的序列化方式的JSON日期轉換與格式化。
前面有好幾篇文章是說明在後端的程式中要如何去對物件資料序列化為JSON,
而物件資料序列化為JSON之後就是要傳給前端去使用,然而JSON資料卻會有個小小的問題存在,
JSON規格中沒有對日期時間的型別去做定義,在 .NET 環境下的日期時間資料在序列化之後卻會有個特別的表示方法,
讓使用者知道某個欄位的資料是個日期型別,
如果是直接已JsonResult的Json方法做資料的序列化,則日期型別的資料會是以下格式:
\/Date(1316747376403)\/
如果是用Json.NET的JsonConvert.SerializeObject()來序列化,則日期型別的資料會是以下格式:
\/Date(1316747376403+0800)\/
除非是在後端的程式中就已經對日期型別的資料去做處理,不然傳到前端的日期資料都還是要再做個處理。
接續「ASP.NET MVC + JSON 自定義JsonResult 1」的內容,
上一篇文章的最後有說,Json.NET所提供的 JsonNetResult類別並不是很適合拿來使用,
而在「使用Entity Framework 將物件轉為JSON時遇到循環參考錯誤 3」裡面,我們也建立了兩個JavaScriptConverter類別,
所以我們就自己來建立一個自己定義的JsonResult,並且使用之前所建立EFJavaScriptSerializer,
這個 EFJavaScriptSerializer 可以分別依據狀況使用 EFSimpleJavaScriptConverter 或 EFJavaScriptConverter…
在「使用Entity Framework 將物件轉為JSON時遇到循環參考錯誤 1」裡面有提到,
如果把EF取出的物件不做任何處理然後在JsonResult中直接使用 Json()方法傳回,會出現「循環參考」的錯誤,
而文章中有提到說可以使用Json.NET所提供的 JsonConvert.SerializeObject()方法來回傳Json資料,
但是必須要使用ActionResult的類別來回傳,而且為了讓Content-Type正確,也需要指定Content-Type,如以下的程式:
public ActionResult Product(int? id)
{ if (!id.HasValue) {Dictionary<string, string> jo = new Dictionary<string, string>();
jo.Add("Msg", "請輸入產品ID編號.");
return Content(JsonConvert.SerializeObject(jo), "application/json");
}
else { ProductService service = new ProductService();var product = service.Single(id.Value);
return Content(JsonConvert.SerializeObject(product), "application/json");
}
}
使用了Json.NET來做為序列化JSON資料的工具,而Json.NET的官網上面也有提供了一個JsonNetResult的類別,
這樣一來在Action就不用再多一個動作去指定使用JsonConvert.Serialize() 方法來序列化資料,
另外也不用使用回傳類別ActionResult,也不用再去指定Content-Type。
接續「使用Entity Framework 將物件轉為JSON時遇到循環參考錯誤 2」
上一篇是說明如何去修改Edmx的屬性「消極式載入已啟用」設定
以及在不修改Edmx的屬性「消極式載入已啟用」的情況下於程式中將LazyLoadingEnable設定為false,
透過這些的修改方式讓物件於序列化為JSON時不去包含或是不載入關連的物件資料。
而這一篇就來看看使用自定義的JavaScriptConverter類別,在不修改上述兩項設定的情形下,
如何做到只序列化物件本身的資料以及序列化物件本身以及其關連的物件資料。
接續「使用Entity Framework 將物件轉為JSON時遇到循環參考錯誤 1」
public ActionResult Product(int? id)
{ if (!id.HasValue) {Dictionary<string, string> jo = new Dictionary<string, string>();
jo.Add("Msg", "請輸入產品ID編號.");
return Content(JsonConvert.SerializeObject(jo), "application/json");
}
else { ProductService service = new ProductService();var product = service.Single(id.Value);
var result = new {ProductID = product.ProductID,
ProductName = product.ProductName,
SupplierID = product.SupplierID,
CategoryID = product.CategoryID,
CategoryName = product.Category.CategoryName,
QuantityPerUnit = product.QuantityPerUnit,
UnitPrice = product.UnitPrice,
UnitsInStock = product.UnitsInStock,
UnitsOnOrder = product.UnitsOnOrder,
ReorderLevel = product.ReorderLevel
};
return Content(JsonConvert.SerializeObject(result), "application/json");
}
}
上面的程式是把Product物件取出後,再去指定要序列化為JSON時所要用的欄位,
但如果每次要對物件做序列化時都要這樣手動去指定也算是一件蠻累人的事情,
尤其是欄位多的時候以及一個物件會在多個地方去做序列化為JSON的操作時,一再重複這樣的事情就會覺得煩。
在ASP.NET MVC的Controller中會經常使用到JSON,通常都是前後端的資料處理,
後端產生物件資料後再轉為JSON傳到前端做AJAX的處理,而後端也會接收前端所傳來的JSON資料,
而ASP.NET MVC的Controller有很多的傳回類別,其中一個有關JSON的就是「JsonResult」,
JsonResult類別
http://msdn.microsoft.com/zh-tw/library/system.web.mvc.jsonresult.aspx
表示用來將JSON格式之內容傳送至回應的類別。(繼承自抽象類別ActionResult)
如果要經由Json(object, JsonRequestBehavior.AllowGet)的方法去傳回JsonResult,結構簡單的物件是不會發生問題的,
例如:
public JsonResult Product(int? id)
{ if (!id.HasValue) {Dictionary<string, string> jo = new Dictionary<string, string>();
jo.Add("Msg", "請輸入產品ID編號.");
return Json(jo, JsonRequestBehavior.AllowGet);}
else { ProductService service = new ProductService();var product = service.Single(id.Value);
var result = new { ID = product.ProductID,
Name = product.ProductName,
CategoryID = product.CategoryID
};
return Json(result, JsonRequestBehavior.AllowGet);}
}
結果:
但如果我們所取得的物件資料不會再去做物件欄位的選擇,而是直接將整個物件放到Json(object)方法中,
而Model的資料模型是使用ASO.NET Entity Framework,各個資料表都有設定關連時,這個時候就很容易出現以下的錯誤:
是的,出現了循環參考的錯誤!怎解呢?