zoukankan      html  css  js  c++  java
  • Asp.Net大型项目实践(5)独家资料!整合NHibernate与Json序列化(附源码)

    注:之所以标题里写独家资料,是我在研究这个问题的时候貌似没有在网上找到相关的解决方案(有也是错的..),自己折腾了半天才搞出来,如果大伙有更好的办法或能找到已有的解决办法可以告诉我 我去掉...

    接上篇,通过NHibernate我们多表查询是实现了 但由于查询出来的集合中的对象“不是平的”,如何在送到UI绑定成了问题。ExtJs UI组件的数据绑定支持多种格式,如简单数组,Json,Xml。在本项目中我们统一,服务器端通过Json把数据传输到Ext进行解析和绑定。

    什么!不知道啥叫Json?

    在这里我们假设Ext对如下的多层嵌套的Json能很好的解析和进行数据绑定(实际上确实如此...)。

    那么我们现在只需要找个方便的办法把我们的.Net对象(集合)转化为Json格式的字符串就可以了。于是乎我们google了一下发现.Net下还真有这么个方法能把.Net对象序列化成Json字符串

    new System.Web.Script.Serialization.JavaScriptSerializer().Serialize([要序列化的.Net对象]);

    Asp.Net Mvc里也有(看过MVC源码后可知,其实里面用的也是上面的JavaScriptSerializer):

    public ActionResult test5()
    {
    return Json([要序列化的Json对象]);
    }

    我们试一试:

    代码
    //Json输出试一试
    public ActionResult test5()
    {
    return Json(new {
    Name
    = "弦哥",
    Age
    = 26,
    IsMarry
    = true,
    MyDog
    = new { Name = "大海", Age = 1, Variety="罗威纳" }
    });
    //小菜注意一下,这个写法叫匿名对象c#3.0下的...
    }

    输出的Json字符串为:

    {"Name":"弦哥","Age":26,"IsMarry":true,"MyDog":{"Name":"大海","Age":1,"Variety":"罗威纳"}}

    于是乎我们兴高采烈的把NHibernate查询出的集合对象也放进去序列化一下:

    代码
    //测试一下
    public ActionResult test()
    {
    Demo.HIS.Infrastructure.Core.Repositories.IDictionaryRepository r
    = new Demo.HIS.Infrastructure.Repositories.Data.DictionaryRepositoryImpl();
    long total;
    var list
    = r.GetPlistByCategoryId("48391bb4-471b-4499-899b-cea9748e1a7b", 0, 15, "Index", "desc", null, out total);

    return Json(list);
    }

    杯具出现鸟....:

    杯具是这样发生的...

     

    于是乎,我们想到自己写Json序列化,可是水平有限...感觉自己写那玩意儿太麻烦,那么能不能找一个可以自定义序列化规则,能自己灵活控制的Json序列化工具呢?

    我们用Json.Net(Newtonsoft.Json),下面我们继承他的DefaultContractResolver类并重写GetSerializableMembers方法 ,定义我们自己的Json序列化规则NHibernateContractResolver,代码如下:

    代码
    namespace Demo.HIS.FrameWork
    {
    /// <summary>
    /// 自定义Json.Net的规则
    /// </summary>
    public class NHibernateContractResolver : DefaultContractResolver
    {
    private string[] exceptMemberName;//例外

    private static readonly MemberInfo[] NHibernateProxyInterfaceMembers = typeof(INHibernateProxy).GetMembers();

    public NHibernateContractResolver(string[] exceptMemberName)
    {
    this.exceptMemberName = exceptMemberName;
    }
    protected override List<MemberInfo> GetSerializableMembers(Type objectType)
    {
    var members
    = new List<PropertyInfo>(objectType.GetProperties());
    members.RemoveAll(memberInfo
    =>
    // (IsMemberNames(memberInfo))||
    (IsMemberPartOfNHibernateProxyInterface(memberInfo))||
    (IsMemberDynamicProxyMixin(memberInfo))
    ||
    (IsMemberMarkedWithIgnoreAttribute(memberInfo,objectType))
    ||
    (IsInheritedISet(memberInfo))
    ||
    (IsInheritedEntity(memberInfo))
    );

    var actualMemberInfos
    = new List<MemberInfo>();
    foreach (var memberInfo in members)
    {
    var infos
    = memberInfo.DeclaringType.BaseType.GetMember(memberInfo.Name);
    actualMemberInfos.Add(infos.Length
    == 0 ? memberInfo : infos[0]);
    //Debug.WriteLine(memberInfo.Name);
    }
    return actualMemberInfos;
    }
    private static bool IsMemberDynamicProxyMixin(PropertyInfo memberInfo)
    {
    return memberInfo.Name == "__interceptors";
    }

    private static bool IsMemberPartOfNHibernateProxyInterface(PropertyInfo memberInfo)
    {
    return Array.Exists(NHibernateProxyInterfaceMembers, mi => memberInfo.Name == mi.Name);
    }

    private static bool IsMemberMarkedWithIgnoreAttribute(PropertyInfo memberInfo, Type objectType)
    {
    var infos
    = typeof(INHibernateProxy).IsAssignableFrom(objectType) ?
    objectType.BaseType.GetMember(memberInfo.Name) :
    objectType.GetMember(memberInfo.Name);
    return infos[0].GetCustomAttributes(typeof(JsonIgnoreAttribute), true).Length > 0;
    }

    private bool IsExceptMember(PropertyInfo memberInfo)
    {
    if (exceptMemberName == null)
    return false;
    return Array.Exists(exceptMemberName, i => memberInfo.Name == i);
    }

    private bool IsInheritedISet(PropertyInfo memberInfo)
    {
    return (memberInfo.PropertyType.Name == "ISet`1" && !IsExceptMember(memberInfo));
    }

    private bool IsInheritedEntity(PropertyInfo memberInfo)
    {
    return (FindBaseType(memberInfo.PropertyType).Name == "Entity" && !IsExceptMember(memberInfo));
    }
    private static Type FindBaseType(Type type)
    {
    if (!type.IsClass)
    return type;
    if (type.Name == "Entity"||type.Name=="Object")
    {
    return type;
    }
    return FindBaseType(type.BaseType);
    }
    }
    }

    代码有点复杂,涉及到对NHibernate动态代理的一些特殊处理,你要问我是咋知道那些稀奇古怪的名儿的?

    注意注释掉的这行 //Debug.WriteLine(memberInfo.Name);

    大概意思就是如果对象里的属性的类型为Entity或ISet<T>的我们就忽略掉,不序列化,除非我们显示指定需要序列化的属性名。

    为了方便Asp.Net MVC调用我们自己的Json序列化,我们自定义一个ActionResult:

    代码
    public class FormatJsonResult : ActionResult
    {
    public string[] ExceptMemberName { get; set; }
    public Object Data { get; set; }
    public override void ExecuteResult(ControllerContext context)
    {
    if (context == null)
    {
    throw new ArgumentNullException("context");
    }
    HttpResponseBase response
    = context.HttpContext.Response;
    response.ContentType
    = "application/json";

    StringWriter sw
    = new StringWriter();
    JsonSerializer serializer
    = JsonSerializer.Create(
    new JsonSerializerSettings
    {
    Converters
    = new JsonConverter[] { new Newtonsoft.Json.Converters.JavaScriptDateTimeConverter() },
    ReferenceLoopHandling
    = ReferenceLoopHandling.Ignore,
    NullValueHandling
    = NullValueHandling.Ignore,
    ContractResolver
    = new NHibernateContractResolver(ExceptMemberName)
    }
    );

    using (JsonWriter jsonWriter = new JsonTextWriter(sw))
    {
    jsonWriter.Formatting
    = Formatting.Indented;
    serializer.Serialize(jsonWriter, Data);
    }
    response.Write(sw.ToString());
    }
    }

    再给Asp.net MVC的Controller类定义两个扩展方法:

    代码
    public static class FormatJsonExtension
    {
    public static FormatJsonResult JsonFormat(this Controller c, object data, string[] exceptMemberName)
    {
    FormatJsonResult result
    = new FormatJsonResult();
    result.Data
    = data;
    result.ExceptMemberName
    = exceptMemberName;
    return result;
    }

    public static FormatJsonResult JsonFormat(this Controller c, object data)
    {
    return JsonFormat(c, data, null);
    }

    }

    最后按照惯例用我们土土的测试方法(高手一般用单元测试-_-b):

    代码
    //测试一下
    public ActionResult test()
    {
    Demo.HIS.Infrastructure.Core.Repositories.IDictionaryRepository r
    = new Demo.HIS.Infrastructure.Repositories.Data.DictionaryRepositoryImpl();
    long total;
    var list
    = r.GetPlistByCategoryId("48391bb4-471b-4499-899b-cea9748e1a7b", 0, 15, "Index", "desc", null, out total);

    //我们自己的Json序列化方法
    return this.JsonFormat(
    list,
    new string[] { "Category" });//指定需要序列化属性“Category”
    }

    然后我们使用工具Fiddler2查看生成的Json,这个工具的使用可以看我同事1-2-3的[推荐]查看Json输出的*最方便*的方法

    成功生成了我们想要的Json如下图:

    这样我们就不必为了Json序列化绑定数据这个原因而搞很多麻烦的尴尬的所谓DTO了

    我们的路子是这样的:NHibernate出的多层对象->自己想要的多层Json->Ext直接绑定

    源码:HISDemo-6.rar

    注意源码里的DemoHisSite我改了下,自己配置下本地的IIS后可运行

  • 相关阅读:
    机器学习之大数据集
    机器学习之协同过滤算法(推荐系统)
    机器学习之异常检测
    机器学习之PCA主成分分析
    机器学习之K-means算法
    机器学习之SVM支持向量机
    机器学习之模型选择与改进
    springmvc spring mybatis插入mysql中文乱码
    springmvc和http404错误
    oracle删除users表空间
  • 原文地址:https://www.cnblogs.com/legendxian/p/1635433.html
Copyright © 2011-2022 走看看