ServiceStack.Text序列化循环引用

我需要像这样序列化一个对象图:

public class A { public B Link1 {get;set;} } public class B { public A Link2 {get;set;} } 

这样json只获得两个实例,但再次正确反序列化。 例如,使用元ID或类似的东西。

我知道Json.NET中有一种方法如下所述: http : //note.harajuku-tech.org/serializing-circular-references-with-jsonnet with meta ids。

ServiceStack.Text Json Serializer中是否有类似的function?

否则,是否可以在ServiceStack使用Json.NET以及如何使用?

编辑:

为了说清楚,我要求提供实例引用,而不仅仅是相同类型。 一个例子可能是:

 [ { "$id": "1", "BroId": 0, "Name": "John", "Bros": [ { "$id": "2", "BroId": 0, "Name": "Jared", "Bros": [ { "$ref": "1" } ] } ] }, { "$ref": "2" } ] 

只有2个对象“真正”序列化,其余的使用$ref属性字段重用。 想象一下具有子项集合的对象模型。 这些子项具有对其父对象的反向引用。 EG客户/订单。 一个客户有多个订单,每个订单都有一个对其客户的引用。 现在想想如果你序列化一个客户会发生什么。

 Customer -> Order -> Customer -> Order -> ... 

而且你会得到类似于这个网站名称的东西。 ;)

我非常喜欢ServiceStack的清晰度,不需要KnownTypeAttribute等。

我希望保持它干净,而不是在我的业务逻辑pocos中实现自定义加载器/对象初始化器。

我通过另一种方式解决了这个问题。 这实际上是有效的,但是当使用具有多个循环引用的更复杂的数据结构时,它可能会出现问题。 但目前没有必要。

我尝试将循环引用function添加到ServiceStack.Text但发现没有必要从它开始。 也许mythz可以给我一个提示? 该function应该非常简单。

我需要这个function来序列化我的数据模型,以完全支持NHibernate的合并function。

我遵循mythz建议,忽略了导致循环引用的IgnoreDataMemberAttribute的属性。 但是这也需要在反序列化之后重建它们,以使合并function正常工作。

– >这是解决方案,现在遵循我的方式:

我开始用一个简单的原型来测试这个,一个数据模型

Customer 1-> n Orders 1-> n Orders

每个类都派生自实体类。

 public class Customer : Entity { public virtual string Name { get; set; } public virtual string City { get; set; } public virtual IList Orders { get; set; } } public class Order : Entity { public virtual DateTime OrderDate { get; set; } public virtual IList OrderDetails { get; set; } [IgnoreDataMember] public virtual Customer Customer { get; set; } } public class OrderDetail : Entity { public virtual string ProductName { get; set; } public virtual int Amount { get; set; } [IgnoreDataMember] public virtual Order Order{ get; set; } } 

如您所见, OrderOrderDetail具有对其父对象的反向引用,这会在序列化时导致循环引用。 这可以通过使用IgnoreDataMemberAttribute忽略后引用来IgnoreDataMemberAttribute

我现在的假设是,在Customer的list属性OrdersOrder每个子实例都有一个对这个Customer实例的反向引用。

所以这就是我重建圆形树的方式:

 public static class SerializationExtensions { public static void UpdateChildReferences(this object input) { var hashDictionary = new Dictionary(); hashDictionary.Add(input.GetHashCode(), input); var props = input.GetType().GetProperties(); foreach (var propertyInfo in props) { if (propertyInfo.PropertyType.GetInterfaces() .Any(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>))) { var instanceTypesInList = propertyInfo.PropertyType.GetGenericArguments(); if(instanceTypesInList.Length != 1) continue; if (instanceTypesInList[0].IsSubclassOf(typeof(Entity))) { var list = (IList)propertyInfo.GetValue(input, null); foreach (object t in list) { UpdateReferenceToParent(input, t); UpdateChildReferences(t); } } } } } private static void UpdateReferenceToParent(object parent, object item) { var props = item.GetType().GetProperties(); var result = props.FirstOrDefault(x => x.PropertyType == parent.GetType()); if (result != null) result.SetValue(item, parent, null); } } 

此代码现在不适用于1-> 1实体引用(不需要),但我认为它可以很容易地扩展。

这现在允许我在客户端有一个POCO类模型,添加/更新/删除子对象并将整个树发送回服务器。 Nhibernate足够聪明地确定哪个实体是新的/更新/删除的。 它也只更新已更改的实体,只更新已更改的属性! 如果删除订单,它还会删除所有OrderDetails。

这是流畅的nhibernate映射的完整性:

 public class CustomerMap : ClassMap { public CustomerMap() { Schema("YOURSCHEMA"); Table("CUSTOMER"); Id(x => x.Id, "ID").GeneratedBy.Assigned(); Map(x => x.Name, "NAM"); Map(x => x.City, "CITY"); HasMany(x => x.Orders) .KeyColumn("CUSTOMER_ID") .Not.LazyLoad() .Inverse() .Cascade.AllDeleteOrphan(); DynamicUpdate(); } } public class OrderMap : ClassMap { public OrderMap() { Schema("YOURSCHEMA"); Table("CUSTOMER_ORDER"); Id(x => x.Id, "ID").GeneratedBy.Assigned(); Map(x => x.OrderDate, "ORDER_DATE"); HasMany(x => x.OrderDetails) .KeyColumn("ORDER_ID") .Not.LazyLoad() .Inverse() .Cascade.AllDeleteOrphan(); References(x => x.Customer, "CUSTOMER_ID"); DynamicUpdate(); } } public class OrderDetailMap : ClassMap { public OrderDetailMap() { Schema("YOURSCHEMA"); Table("ORDER_DETAIL"); Id(x => x.Id, "ID").GeneratedBy.Assigned(); Map(x => x.ProductName, "PRODUCT_NAME"); Map(x => x.Amount, "AMOUNT"); References(x => x.Order, "ORDER_ID"); DynamicUpdate(); } } 

DynamicUpdate()用于让nhibernate仅更新已更改的属性。 您现在只需要使用ISession.Merge(customer)function来正确保存所有内容。

ServiceStack默认支持循环引用。

为什么不在发布之前先自己尝试validation是否存在实际问题? 这比创建一个新问题并要求其他人这样做更省力。

按照你的例子:

 public class A { public string Name { get; set; } public B Link1 { get; set; } } public class B { public string Name { get; set; } public A Link2 { get; set; } } var dto = new A { Name = "A1", Link1 = new B { Name = "B1", Link2 = new A { Name = "A2" } } }; dto.ToJson().Print(); 

将打印JSON字符串:

 {"Name":"A1","Link1":{"Name":"B1","Link2":{"Name":"A2"}}} 

虽然将它序列化为JSON并再次反序列化,如:

 var fromJson = dto.ToJson().FromJson(); fromJson.PrintDump(); 

将转储内容:

 { Name: A1, Link1: { Name: B1, Link2: { Name: A2 } } } 

如果有人需要能够使用循环序列化对象图,JSON.NET确实支持它:

 new JsonSerializer { PreserveReferencesHandling = PreserveReferencesHandling.Objects };