Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON.Net Serialization of NHibernate Proxies (NH 3.3.2.4000)

I'm still having continuous difficulties getting Json.Net and NHibernate to play nicely together. Namely, in getting Json.NET to serialize a proxied NHibernate object.

I've followed the recommendations here, both for the accepted answer and the ammendments, but no dice.

The biggest problem with the above solution is that it seems that modern versions of NHibernate are using the INHibernateProxyProxy interface to create proxies (rather than INHibernateProxy? Can anyne else confirm this?), whose base class in my case is NHibernate.Proxy.DynamicProxy.ProxyDummy, which reveals nothing about the underlying object when I attempt to create the Json constract using my custom scontract resolver, ie:

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

Does anyone have any advice for how to deal with INHibernateProxyProxy effectively?

like image 538
Stumblor Avatar asked Oct 03 '22 06:10

Stumblor


2 Answers

The full Solution:

In 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();
        //------------//

And the custom contract:

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

Don't forget to replace : "Your.Domain.Namespace"

like image 188
Matias Dipaolo Avatar answered Oct 11 '22 13:10

Matias Dipaolo


Found it. The original type is available via .GetInterfaces(), ie:

    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);
    }
like image 31
Stumblor Avatar answered Oct 11 '22 13:10

Stumblor