Asp.Net大型项目实践(5)-独家资料!整合NHibernate与Json序列化(附源码)

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

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

什么!不知道啥叫Json?
Asp.Net大型项目实践(5)-独家资料!整合NHibernate与Json序列化(附源码)_第1张图片

 

 

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

Asp.Net大型项目实践(5)-独家资料!整合NHibernate与Json序列化(附源码)_第2张图片

 

 

那么我们现在只需要找个方便的办法把我们的.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);
}

杯具出现鸟....:

Asp.Net大型项目实践(5)-独家资料!整合NHibernate与Json序列化(附源码)_第3张图片

杯具是这样发生的...

 Asp.Net大型项目实践(5)-独家资料!整合NHibernate与Json序列化(附源码)_第4张图片

于是乎,我们想到自己写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如下图:

Asp.Net大型项目实践(5)-独家资料!整合NHibernate与Json序列化(附源码)_第5张图片

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

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

源码:HISDemo-6.rar

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

你可能感兴趣的:(Hibernate)