DynamicObject 是 .NET 4.0以來才支持的一個類,但該類在.NET 4.0下未被標記爲[Serializable] Attribute,而在.NET 4.5下則被標記了[Serializable] Attribute。須要注意的是,若是你使用須要進行XML序列化等操做(例如WCF中),部署到未安裝.NET 4.5的環境中一般會報錯並提示異常,而無論你編譯時使用的目標平臺是.NET 4.0 仍是 .NET 4.5。一般這個錯誤在安裝了.NET 4.5環境的開發機上一般沒有問題,即便你建立的項目是基於.NET 4.0的,但實際調用的仍是 .NET 4.5的庫。所以一般在使用 DynamicObject 並須要進行序列化的情景下須要謹慎(特別是WCF環境下),除非你實現了你自定義的序列化操做。在此提醒廣大開發人員注意,不然到你正式部署至不能安裝.NET 4.5的環境中將折騰你夠嗆(例如Windows Server 2003等環境)。html
在前文:「實體類配合數據庫表字段進行屬性擴展」 一文中介紹瞭如何使用 DynamicObject 進行屬性的擴展,但該類在MVC下進行JSON序列化時其序列化的結果並不友好。本文主要討論的是如何友好地對 DynamicObject 繼承類進行JSON序列化。數據庫
要對 DynamicObject 對象實現JSON的序列化,其實只需在 DynamicObject 的繼承類中實現 IDictionary<string,object> 接口便可,由於 JavaScriptSerializer 和 Json.NET 均支持對 IDictionary<string,object> 的序列化,該接口主要對 DynamicObject 對象的屬性和值進行管理。前文所述的ExtensionObject類就繼承自DynamicObject類,並實現了 IDynamicMetaObjectProvider 和 IDictionary<string,object> 接口。json
在MVC中原生態的 JavascrioptSerializer 序列化時會使用 IDictionary<string,object> 的實現方法 System.Collections.IEnumerable.GetEnumerator() 來獲取要序列化的屬性名。api
而Json.NET則調用 IDictionary<string,object> 的實現方法 IEnumerable<KeyValuePair<string, object>>.GetEnumerator() 來獲取屬性及其值。app
但兩者最大的區別是,使用JavascrioptSerializer將序列化成以下的JSON格式:框架
{{"Key":"Code","Value":"4"},{"Key":"ID","Value":"d8ea26b06d9d4c7e85ccc43da71320ac"},{"Key":"LongName","Value":"null"}, {"Key":"FCode","Value":"/51/5100/4"},{"Key":"NodeLevel","Value":"3"}}ide
而使用Json.NET則序列化爲:{"ID": "d8ea26b06d9d4c7e85ccc43da71320ac","Code": "4","LongName": null,"FCode": "/51/5100/4","NodeLevel": 3}oop
毫無疑問,使用Json.NET進行序列化更符合實際的狀況和須要,並且速度還更快。固然,在WebApi下,由於已使用了Json.NET做爲默認的序列化組件,並不存在上述問題,所以本文將主要對MVC中對DynamicObject的Json.NET序列化的實現進行說明。性能
1、MVC下使用Json.NET序列化ui
一、實現自定義ActionResult,繼承自JsonResult類,代碼以下:
using System; using System.Web.Mvc; using Newtonsoft.Json; using Newtonsoft.Json.Converters; namespace YbRapidSolution.Presenter.JsonNet { public class JsonNetResult : JsonResult { public JsonSerializerSettings SerializerSettings { get; set; } public JsonNetResult() : base() { // create serializer settings this.SerializerSettings = new JsonSerializerSettings(); // 阻止屬性循環引用的狀況下出現的異常 this.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; // setup default serializer settings this.SerializerSettings.Converters.Add(new IsoDateTimeConverter()); } public JsonNetResult(string contentType) : this() { ContentType = contentType; } public JsonNetResult(string contentType, System.Text.Encoding contentEncoding) : this(contentType) { ContentEncoding = contentEncoding; } public override void ExecuteResult(ControllerContext context) { if (context == null) throw new ArgumentNullException("context"); if (JsonRequestBehavior == JsonRequestBehavior.DenyGet && String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException("Json request GET not allowed"); } // 獲取當前 http context response var response = context.HttpContext.Response; // 設置 content type response.ContentType = !String.IsNullOrEmpty(ContentType) ? ContentType : "application/json"; // 設置 encoding if (ContentEncoding != null) response.ContentEncoding = this.ContentEncoding; if (Data != null) { // 使用 JSON.Net 把對象序列化爲 JSON string jsonText = JsonConvert.SerializeObject(this.Data, Formatting.Indented, this.SerializerSettings); // write the response response.Write(jsonText); } } } }
二、對Controller進行方法的擴展
using System.Dynamic; using System.Web.Mvc; using YbRapidSolution.Presenter.Controllers; namespace YbRapidSolution.Presenter.JsonNet { public static class JsonNetControllerExtensions { public static JsonNetResult JsonNet(this Controller controller, object data) { return new JsonNetResult() { Data = data }; } public static JsonNetResult JsonNet(this Controller controller, object data,string contentType) { return new JsonNetResult(contentType) { Data = data }; } } }
三、調用方式的Demo以下:
/// <summary> /// 查找當前登陸用戶的當前崗位對本模塊所具備的動做權限集合 /// </summary> /// <param name="orgFId">當前登陸用戶所使用的崗位(人員成員)的標識全路徑</param> /// <returns></returns> [AcceptVerbs(HttpVerbs.Post)] [YbMvcAuthorize(PermissionKeys = PERMISSIONKEY)] public JsonResult FindAllowActionsFor(string orgFId) { try { var curMessage = new EasyUIMessage(true, "權限項加載成功"); //查詢類型爲按鈕或右鍵菜單的動做 var actions = _permissionService .FindControlsForOrgByKeyAndOrgFId(PERMISSIONKEY,orgFId); curMessage.data = actions; return this.JsonNet(curMessage); } catch (Exception er) { var curMessage = new EasyUIMessage(false, string.Format("權限項加載失敗:{0}", er.Message)); return this.JsonNet(curMessage); } }
2、Web Api下使用Json.NET序列化
Web Api由於使用Json.NET做爲默認的JSON序列化實現框架,一般需在 WebApiConfig 類的 Register 中寫以下的代碼進行配置便可:
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize; config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
如需瞭解更多請點擊:權限模型+流程專家 Demo
下一章將分享WebApi和MVC下的提高性能的一些經驗。