我仍然让Json.Net和NHibernate一起玩得很好。即,让Json.NET序列化代理的NHibernate对象。
我已遵循建议here,既接受了答案,又接受了修正案,但没有骰子。
上述解决方案的最大问题是,NHibernate的现代版本似乎正在使用INHibernateProxyProxy
接口来创建代理(而不是INHibernateProxy?还有其他人可以确认吗?),在我的情况下它的基类是NHibernate.Proxy.DynamicProxy.ProxyDummy
,当我尝试使用我的自定义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);
}
有没有人对如何有效处理INHibernateProxyProxy
有任何建议?
答案 0 :(得分: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);
}
不要忘记更换:&#34; Your.Domain.Namespace&#34;
答案 1 :(得分: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);
}
答案 2 :(得分: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
事件执行此操作,但我只是直接在我的服务方法中处理它。
答案 3 :(得分: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()
});
这解决了我的问题。