5

仍然很难让 Json.Net 和 NHibernate 一起玩得很好。即,让 Json.NET 序列化代理的 NHibernate 对象。

我已经遵循了这里的建议,包括接受的答案和修正案,但没有骰子。

上述解决方案的最大问题是,现代版本的 NHibernate 似乎正在使用该INHibernateProxyProxy接口来创建代理(而不是 INHibernateProxy?还有其他人可以证实这一点吗?),在我的例子中NHibernate.Proxy.DynamicProxy.ProxyDummy,它的基类是当我尝试使用我的自定义 scontract 解析器创建 Json 合约时对象,即:

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

有人对如何INHibernateProxyProxy有效处理有任何建议吗?

4

4 回答 4

2

完整的解决方案:

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

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

于 2016-01-29T16:02:08.557 回答
1

找到了。原始类型可通过 获得.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);
    }
于 2013-08-13T13:04:07.337 回答
1

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

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

之后,BaseType可能是正确的......即不是ProxyDummy,而是需要的实际类型。

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

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.
        };
    }
}

所以当我有一个代理类型的 REST 服务端点时,它看起来像这样:

[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事件来做到这一点,但我只是直接在我的服务方法中处理它。

于 2015-11-19T02:15:45.277 回答
0

我的问题是,并非所有子列表都由 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()
        });

这解决了我的问题。

于 2018-06-26T10:38:04.620 回答