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底层组件帮助文档

下一章将分享WebApi和MVC下的提升性能的一些经验。

时间: 2024-12-21 03:18:08

YbSoftwareFactory 代码生成插件【二十】:DynamicObject的序列化的相关文章

YbSoftwareFactory 代码生成插件【十九】:实体类配合数据库表字段进行属性扩展的小技巧

实体类通常需要和数据库表进行了ORM映射,当你需要添加新的属性时,往往同时也需要在数据库中添加相应的字段并配置好映射关系,同时可能还需对数据访问组件进行重新编译和部署才能有效.而当你开始设计一个通用数据访问组件后,因为项目需求的不同和需求的不断变化演变,很难不能保证不会再添加额外的属性和字段.特别是项目部署运行后,添加一个属性和字段带来的额外维护的工作量可能要远远超过对代码进行调整的工作量.本文提供了属性字段扩展的一种思路,在满足核心字段可通过实体类强类型进行访问的同时,还可通过C# 4.0提供

YbSoftwareFactory 代码生成插件【十八】:树形结构下的查询排序的数据库设计

树形结构的排序在中国特色下十分普遍也非常重要,例如常说的五大班子,党委>人大>政府>政协>纪委,每个班子下还有部门,岗位,人员,最终排列的顺序通常需要按权力大小.重要性等进行排列,顺序排列不好可是重大的罪过,领导很生气,后果很严重.这种排序方式本质上就是典型的树形结构深度排序,但在数据库中很难直接通过SQL语句简单高效地进行处理,更不用说还要支持不同类型数据库了. 当前解决此类问题,主要有两种方法. 1. 排序码方式 原理:在每个树形节点上均设置一个排序码,排序码通常是一个字符串并

YbSoftwareFactory 代码生成插件【二十五】:Razor视图中以全局方式调用后台方法输出页面代码的三种方法

上一篇介绍了 MVC中实现动态自定义路由 的实现,本篇将介绍Razor视图中以全局方式调用后台方法输出页面代码的三种方法. 框架最新的升级实现了一个页面部件功能,其实就是通过后台方法查询数据库内容,把查询结果的 HTML 代码呈现到 Razor 视图中,考虑到灵活性,需要能在任意 Razor 视图中调用该方法,这样任意 Razor 页面都能以统一的方式方便地共享该页面部件的 HTML 内容,这对于代码的重用性和可维护性都是非常有必要的. 为实现上述要求,本文介绍如下可供选择的三种方式.   1.

YbSoftwareFactory 代码生成插件【二十四】:MVC中实现动态自定义路由

上一篇介绍了 公文流转系统 的实现,本篇介绍下MVC下动态自定义路由的实现. 在典型的CMS系统中,通常需要为某个栏目指定个友链地址,通过指定友链地址,该栏目的地址更人性化.方便记忆,也有利用于搜索引擎优化. 但在MVC中,通常需要在应用程序启动时注册路由规则,该路由规则又通常和控制器进行了关联,也就是某个地址通常情况下都是有对应的控制器进行处理的.但在MVC中如何做到自定义动态路由,以便能在运行时通过某个控制器处理一些运行时动态设定的Url地址呢? 方法当然是有的:    1.首先实现一个动态

YbSoftwareFactory 代码生成插件【二十二】:CMS基础功能的实现

很多网友建议在YbRapidSolution for MVC框架的基础上实现CMS功能,以方便进行内容的管理,加快前端页面的开发速度.因此花了一段时间,实现了一套CMS内容发布系统并已集成至YbRapidSolution for MVC框架中. 本CMS当前实现了CMS参数设置.栏目管理.文章管理.文档管理.评论管理.问卷调查等功能.首先看看本CMS使用的主要技术及其整体架构图: 上图中的架构可以说和YbRapidSolution for MVC的架构基本是一致的,如下将对主要的技术要点进行总结

YbSoftwareFactory 代码生成插件【二十一】:Web Api及MVC性能提升的几个小技巧

最近在进行 YbSoftwareFactory 的流程功能升级,目前已经基本完成,现将用到的一些关于 Web Api 及 MVC 性能提升的一些小技巧进行了总结,这些技巧在使用.配置上也相当的简单,但通常都能大大提高应用程序的性能,希望对大家有用. 一.缓存 为了避免每次请求都去访问后台的资源,我们一般会考虑将一些更新不是很频繁的,可以重用的数据,通过一定的方式临时地保存起来,后续的请求根据情况可以直接访问这些保存起来的数据,这种机制就是所谓的缓存机制.缓存分为页面输出缓存,内存数据缓存和缓存依

YbSoftwareFactory 代码生成插件【二十三】:集成强大的公文流转系统

今天有空更新博客才发现快一年没有写博客了,不得不感叹时间过得真快.过去的一年确实也挺忙的,在此祝各位博友们新的一年工作顺利.权限模型在过去一年进行了不少的升级,主要集成了公文流转系统.多家手机短信接口的集成.CMS动态路由的实现.以及Hangfire消息队列与任务调度组件的集成等,本章主要对公文流转系统进行总体的介绍,感兴趣的可进一步交流或访问http://pjdemo.yellbuy.com. 公文流转系统是国内企事业单位的普遍需求,具有很强的中国特色.通常其核心需求如下: 具备公文流程审批,

Python学习笔记(二十五)序列化_JSON基础

摘抄自:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143192607210600a668b5112e4a979dd20e4661cc9c97000 本文章完全用于个人复习使用,侵删: 把变量从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling. 序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上. 反过来,把变量内容从序

android产品研发(二十二)--&gt;android实用调试技巧

转载请标明出处:一片枫叶的专栏 上一篇文章中我们讲解了android UI优化方面的知识.我们讲解了android中的include.marge.ViewStub标签,在使用这些标签时可以简化我们的布局文件,优化组件绘制流程:讲解了android中的过度绘制相关知识点,通过优化我们的App过度绘制可以提高App的UI绘制流程与性能:我们还讲解了App中一些UI优化的小tips.更多关于android UI优化方面的知识可以参考我的:android产品研发(二十一)–>android中的UI优化