NHibernate代理的JSON.Net序列化(NH3.3.2.4000)

NHibernate代理的JSON.Net序列化(NH3.3.2.4000),nhibernate,proxy,json.net,Nhibernate,Proxy,Json.net,要让Json.Net和NHibernate很好地协同工作,我仍然有很多困难。也就是说,让Json.NET序列化代理的NHibernate对象 我已经遵循了这些建议,包括公认的答案和附录,但没有选择 上述解决方案的最大问题是,NHibernate的现代版本似乎正在使用INHibernateProxy接口来创建代理(而不是INHibernateProxy?还有人能证实这一点吗?),在我的例子中,其基类是NHibernate.Proxy.dynamicProxyDummy,当我尝试使用我的自定义sco

要让Json.Net和NHibernate很好地协同工作,我仍然有很多困难。也就是说,让Json.NET序列化代理的NHibernate对象

我已经遵循了这些建议,包括公认的答案和附录,但没有选择

上述解决方案的最大问题是,NHibernate的现代版本似乎正在使用
INHibernateProxy
接口来创建代理(而不是INHibernateProxy?还有人能证实这一点吗?),在我的例子中,其基类是
NHibernate.Proxy.dynamicProxyDummy
,当我尝试使用我的自定义scontract解析器创建Json constract时,它没有显示任何关于底层对象的信息,即:

    protected override JsonContract CreateContract(Type objectType)
    {
        if (typeof(NHibernate.Proxy.INHibernateProxy).IsAssignableFrom(objectType))
            return base.CreateContract(objectType.BaseType);
        else
            return base.CreateContract(objectType);
    }

有人对如何有效地处理ibernateproxyproxy中的
有什么建议吗?

找到了。原始类型可通过
.GetInterfaces()
获得,即:

    protected override JsonContract CreateContract(Type objectType)
    {
        if (typeof (INHibernateProxy).IsAssignableFrom(objectType))
        {
            var oType = objectType.GetInterfaces().FirstOrDefault(i => i.FullName.StartsWith("Your.Domain.Namespace"));
            return oType != null ? base.CreateContract(oType) : base.CreateContract(objectType.BaseType);
        }
        return base.CreateContract(objectType);
    }

从很久以前开始,但我认为这里的问题实际上是代理在尝试序列化之前没有初始化

您必须调用
NHibernateUtil.Initialize(aPersistentObject.LazyProperty)
初始化代理对象

之后,
BaseType
可能是正确的。。。i、 e.不是
proxymdummy
,而是所需的实际类型

对我来说,解决方案是这样的:

namespace com.example.DataAccess
{
    public static class Helper
    {
        // the implementation I use creates a ThreadStatic ISession, 
        // and then orphans and disposes that ISession when the 
        // result of this method is disposed.
        public static IDisposable GetSession(); 

        public static Type GetUnproxiedType(Type objectType)
        {
            if (typeof(INhibernateProxy).IsAssignableFrom(objectType))
                return objectType.BaseType;
            return objectType;
        }
        public static void Initialize(object proxy)
        {
            NHibernateUtil.Initialize(proxy);
        }
    }
}

namespace com.example.WebService
{
    internal static class Helper
    {
        private class ProxyResolver : CamelCasePropertyNamesContractResolver
        {
            protected override JsonContract CreateContract(Type objectType)
            {
                return base.CreateContract(DataAccess.Helper.GetUnproxiedType(objectType));
            }
        }

        public static readonly JsonSerializer serializer = new JsonSerializer
        {
            ContractResolver = new ProxyResolver(),
            Converters = 
                { 
                    new StringEnumConverter(),
                },
            DateFormatHandling = Newtonsoft.Json.DateFormatHandling.IsoDateFormat,
            Formatting = Formatting.Indented,
            // etc.
        };
    }
}
[WebGet(UriTemplate= "foo/{id}/bar")]
public Bar GetFooBar(string id)
{
    using (DataAccess.Helper.GetSession())
    {
        var foo = GetFoo(id);
        if (foo == null) return null;
        DataAccess.Helper.Initialize(foo.Bar);
        return foo.Bar;
    }
}
因此,当我有一个具有代理类型的REST服务端点时,它看起来是这样的:

namespace com.example.DataAccess
{
    public static class Helper
    {
        // the implementation I use creates a ThreadStatic ISession, 
        // and then orphans and disposes that ISession when the 
        // result of this method is disposed.
        public static IDisposable GetSession(); 

        public static Type GetUnproxiedType(Type objectType)
        {
            if (typeof(INhibernateProxy).IsAssignableFrom(objectType))
                return objectType.BaseType;
            return objectType;
        }
        public static void Initialize(object proxy)
        {
            NHibernateUtil.Initialize(proxy);
        }
    }
}

namespace com.example.WebService
{
    internal static class Helper
    {
        private class ProxyResolver : CamelCasePropertyNamesContractResolver
        {
            protected override JsonContract CreateContract(Type objectType)
            {
                return base.CreateContract(DataAccess.Helper.GetUnproxiedType(objectType));
            }
        }

        public static readonly JsonSerializer serializer = new JsonSerializer
        {
            ContractResolver = new ProxyResolver(),
            Converters = 
                { 
                    new StringEnumConverter(),
                },
            DateFormatHandling = Newtonsoft.Json.DateFormatHandling.IsoDateFormat,
            Formatting = Formatting.Indented,
            // etc.
        };
    }
}
[WebGet(UriTemplate= "foo/{id}/bar")]
public Bar GetFooBar(string id)
{
    using (DataAccess.Helper.GetSession())
    {
        var foo = GetFoo(id);
        if (foo == null) return null;
        DataAccess.Helper.Initialize(foo.Bar);
        return foo.Bar;
    }
}
WebService.Helper
中定义的序列化程序用于序列化结果

请注意,如果序列化过程发生在方法之外(对我来说也是如此),则在实际序列化对象之前,始终需要调用初始化对象。您可以通过
Global.asax
事件来实现这一点,但我只是在我的服务方法中直接处理它。

完整的解决方案:

在Global.asax.cs中:

 //Define Formatters
        var formatters = GlobalConfiguration.Configuration.Formatters;
        var jsonFormatter = formatters.JsonFormatter;
        var settings = jsonFormatter.SerializerSettings;
        settings.Formatting = Formatting.Indented;           
        jsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize;
        jsonFormatter.SerializerSettings.PreserveReferencesHandling  = Newtonsoft.Json.PreserveReferencesHandling.Objects;
        jsonFormatter.SerializerSettings.ContractResolver = new NHibernateContractResolver();
        //------------//
和海关合同:

public class NHibernateContractResolver : DefaultContractResolver
{
    private static readonly MemberInfo[] NHibernateProxyInterfaceMembers = typeof(INHibernateProxy).GetMembers();

    protected override List<MemberInfo> GetSerializableMembers(Type objectType)
    {
        var members = base.GetSerializableMembers(objectType);

        members.RemoveAll(memberInfo =>
                          (IsMemberPartOfNHibernateProxyInterface(memberInfo)) ||
                          (IsMemberDynamicProxyMixin(memberInfo)) ||
                          (IsMemberMarkedWithIgnoreAttribute(memberInfo, objectType)) ||
                          (IsMemberInheritedFromProxySuperclass(memberInfo, objectType)));

        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]);
        }

        return actualMemberInfos;
    }

    private static bool IsMemberDynamicProxyMixin(MemberInfo memberInfo)
    {
        return memberInfo.Name == "__interceptors";
    }

    private static bool IsMemberInheritedFromProxySuperclass(MemberInfo memberInfo, Type objectType)
    {
        return memberInfo.DeclaringType.Assembly == typeof(INHibernateProxy).Assembly;
    }

    private static bool IsMemberMarkedWithIgnoreAttribute(MemberInfo 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 static bool IsMemberPartOfNHibernateProxyInterface(MemberInfo memberInfo)
    {
        return Array.Exists(NHibernateProxyInterfaceMembers, mi => memberInfo.Name == mi.Name);
    }


protected override JsonContract CreateContract(Type objectType)
{
    if (typeof(INHibernateProxy).IsAssignableFrom(objectType))
    {
        var oType = objectType.GetInterfaces().FirstOrDefault(i => i.FullName.StartsWith("Your.Domain.Namespace"));
        return oType != null ? base.CreateContract(oType) : base.CreateContract(objectType.BaseType);
    }
    return base.CreateContract(objectType);
}
公共类NHibernateContractResolver:DefaultContractResolver
{
private static readonly MemberInfo[]nhibernateproxy接口成员=typeof(INHibernateProxy).GetMembers();
受保护的覆盖列表GetSerializableMembers(类型objectType)
{
var members=base.GetSerializableMembers(objectType);
members.RemoveAll(memberInfo=>
(IsMemberPartOfHibernateProxy接口(memberInfo))||
(IsMemberDynamicProxyMixin(成员信息))||
(IsMemberMarkedWithIgnoreAttribute(memberInfo,objectType))||
(IsMemberInheritedFromProxySuperclass(memberInfo,objectType));
var actualMemberInfos=新列表();
foreach(成员中的var memberInfo)
{
var infos=memberInfo.DeclaringType.BaseType.GetMember(memberInfo.Name);
ActualMemberInfo.Add(infos.Length==0?memberInfo:infos[0]);
}
返回实际成员数;
}
私有静态bool IsMemberDynamicProxyMixin(MemberInfo MemberInfo)
{
returnmemberinfo.Name==“\uuuu拦截器”;
}
私有静态bool IsMemberInheritedFromProxySuberclass(MemberInfo MemberInfo,类型objectType)
{
return memberInfo.DeclaringType.Assembly==typeof(INHibernateProxy).Assembly;
}
私有静态bool IsMemberMarkedWithIgnoreAttribute(MemberInfo MemberInfo,类型objectType)
{
var infos=typeof(INHibernateProxy).IsAssignableFrom(objectType)
?objectType.BaseType.GetMember(memberInfo.Name)
:objectType.GetMember(memberInfo.Name);
返回信息[0]。GetCustomAttributes(typeof(JsonIgnoreAttribute),true)。长度>0;
}
私有静态bool IsMemberPartOfHibernateProxy接口(MemberInfo MemberInfo)
{
返回Array.Exists(nhibernateproxy接口成员,mi=>memberInfo.Name==mi.Name);
}
受保护的重写JsonContract CreateContract(类型objectType)
{
if(typeof(INHibernateProxy).IsAssignableFrom(objectType))
{
var oType=objectType.GetInterfaces().FirstOrDefault(i=>i.FullName.StartsWith(“Your.Domain.Namespace”);
返回oType!=null?base.CreateContract(oType):base.CreateContract(objectType.BaseType);
}
返回base.CreateContract(objectType);
}

不要忘记替换:“Your.Domain.Namespace”

我的问题是并非所有子列表都由Newtonsoft.JSON解决

我添加了一个合同解析器

public class ProjectContractResolver : DefaultContractResolver
{
    protected override JsonContract CreateContract(Type objectType)
    {
        if (typeof(INHibernateProxy).IsAssignableFrom(objectType))
        {
            if (objectType.FullName.Equals("DeviceModelProxy"))
                return CreateContract(typeof(DeviceModel));

            if (objectType.FullName.Equals("JobModelProxy"))
                return CreateContract(typeof(JobModel));

            base.CreateContract(objectType.BaseType);
        }
        return base.CreateContract(objectType);
    }
}
JsonConvert.SerializeObject(backupDataModel, Formatting.Indented, new JsonSerializerSettings()
        {
            ContractResolver = new ProjectContractResolver()
        });
在序列化时添加自定义协定解析程序

public class ProjectContractResolver : DefaultContractResolver
{
    protected override JsonContract CreateContract(Type objectType)
    {
        if (typeof(INHibernateProxy).IsAssignableFrom(objectType))
        {
            if (objectType.FullName.Equals("DeviceModelProxy"))
                return CreateContract(typeof(DeviceModel));

            if (objectType.FullName.Equals("JobModelProxy"))
                return CreateContract(typeof(JobModel));

            base.CreateContract(objectType.BaseType);
        }
        return base.CreateContract(objectType);
    }
}
JsonConvert.SerializeObject(backupDataModel, Formatting.Indented, new JsonSerializerSettings()
        {
            ContractResolver = new ProjectContractResolver()
        });

这就解决了我的问题。

这是一个自定义合同解析程序,它派生自DefaultContractResolver。更多信息。