YbSoftwareFactory 代碼生成插件【二十】:DynamicObject的序列化


    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等環境)。

    在前文:“實體類配合數據庫表字段進行屬性擴展” 一文中介紹了如何使用 DynamicObject 進行屬性的擴展,但該類在MVC下進行JSON序列化時其序列化的結果並不友好。本文主要討論的是如何友好地對 DynamicObject 繼承類進行JSON序列化。

    要對 DynamicObject 對象實現JSON的序列化,其實只需在 DynamicObject 的繼承類中實現 IDictionary<string,object> 接口即可,因為 JavaScriptSerializer 和 Json.NET 均支持對 IDictionary<string,object> 的序列化,該接口主要對 DynamicObject 對象的屬性和值進行管理。前文所述的ExtensionObject類就繼承自DynamicObject類,並實現了 IDynamicMetaObjectProvider 和 IDictionary<string,object> 接口。

    在MVC中原生態的 JavascrioptSerializer 序列化時會使用 IDictionary<string,object> 的實現方法 System.Collections.IEnumerable.GetEnumerator() 來獲取要序列化的屬性名。

    而Json.NET則調用 IDictionary<string,object> 的實現方法 IEnumerable<KeyValuePair<string, object>>.GetEnumerator() 來獲取屬性及其值。

    但二者最大的區別是,使用JavascrioptSerializer將序列化成如下的JSON格式:

{{"Key":"Code","Value":"4"},{"Key":"ID","Value":"d8ea26b06d9d4c7e85ccc43da71320ac"},{"Key":"LongName","Value":"null"},           {"Key":"FCode","Value":"/51/5100/4"},{"Key":"NodeLevel","Value":"3"}}

    而使用Json.NET則序列化為:{"ID": "d8ea26b06d9d4c7e85ccc43da71320ac","Code": "4","LongName": null,"FCode": "/51/5100/4","NodeLevel": 3}

    毫無疑問,使用Json.NET進行序列化更符合實際的情況和需要,而且速度還更快。當然,在WebApi下,因為已使用了Json.NET作為默認的序列化組件,並不存在上述問題,因此本文將主要對MVC中對DynamicObject的Json.NET序列化的實現進行說明。

    一、MVC下使用Json.NET序列化

    1、實現自定義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);
            }
        }
    }
}

    2、對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 };
        }
    }
}

    3、調用方式的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);
            }
        }

    二、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

    附一:ExtensionObject源碼

    附二:YbSoftwareFactory操作手冊

    附三:YbSoftwareFactory底層組件幫助文檔

    下一章將分享WebApi和MVC下的提升性能的一些經驗。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM