如何使用$ref和$id在 RestKit 中使用循环引用



我有一个使用 json.net 序列化库的API。它使用$ref和$id字段进行循环引用。RestKit 没有意识到这些$ref字段正在引用另一个已序列化的对象。

有没有办法告诉 RestKit 使用这些字段,这样就不会创建空对象?

这是我的 json 示例:

{
"$id":"1",
"WorkOrder":{
"$id":"2",
"Location":{
"$id":"3",
"Address":{
"$id":"4",
"Guid":"8086990f-13a0-4f93-8a9b-043ff247ae66"
},
"WorkOrders":[
{
"$ref":"2"
}
],
"Guid":"ae58698d-4fcf-4c31-82bf-529077b6d059"
},
"Appointments":[
{
"$ref":"1"
}
],
"Guid":"94140fc6-9885-4395-a79d-2b60452f2bf4",
},
"Calendar":{
"$id":"5",
"OwnerID":"1bbda60d-0bda-4b97-b6e5-24460106bc54",
"IsActive":true,
"Appointments":[
{
"$ref":"1"
}
],
"Guid":"e6c91678-290d-4d12-b52f-9f6ad36dd679",
},
"Guid":"731f20c6-6ecb-4515-ade3-df47bc929c86",
}

答案不在于 RestKit,而在于您的 JSON.Net 序列化。 以下是问题:

  • RestKit不知道如何处理$ref,$id
  • 您有一个 WCF 服务层,它将对象返回到 API 层 (MVC APIController)。
  • 您的 API 层希望将对象序列化为 JSON 到客户端。
  • WCF 需要将对象作为引用进行管理,否则将发生堆栈溢出,并且您的服务将只将对象转移到 API。
  • API 层不需要$ref $id引用,因为 RestKit 无法处理。
  • RestKit 可以将空对象作为仅包含对象主键的引用进行处理。 RestKit 将对该对象执行更新插入,只有主键,它将看到该对象已经存在,并且没有其他数据要更新,因此它将完美地处理引用。

因此,为了实现这一点,我们需要使用 WCF 引用将对象从服务层获取到 API 层,然后仅使用对象的主键作为引用而不是 WCF 使用的$id $ref废话来创建我们自己的 json 序列化。

所以,这里是细节。

首先,您正在获得$ref $id,因为您正在调用 WCF 服务,该服务的类使用[DataContract(IsReference=true)]属性进行修饰。 JSON.Net 序列化程序将读取此属性并创建$id,如果您没有使用[JsonObject(IsReference=false)]修饰类,则$ref引用。 您需要 DataContract IsReference 才能使 WCF 服务将对象序列化到 ApiController。 您的 ApiController 现在希望将对象序列化为客户端作为 Json...因此,您的对象还需要 Json(IsReference=false) 来防止$id,$ref

因此,这是数据模型类定义现在的样子

[JsonObject(IsReference=false)]
[DataContract(IsReference=true)]
public class SomeClassToSerialize

DataContract 来自 System.Runtime.Serialization lib JsonObject 来自 NewtonSoft.Json lib

好的......这已经解决了一半。 此时,我们将使用 WCF 引用将服务中的对象返回到我们的 api。 我们已经告诉我们的 API 不要使用引用,所以我们的 API 服务现在将因堆栈溢出而崩溃,因为它将尝试序列化循环引用。

下一步是创建一个自定义JsonConverter,该将仅使用主键呈现循环引用。 在下面的示例中,我的所有对象都继承自 EntityBase。 所有这些的主键是一个名为 Guid 的 Guid。 所以,这是逻辑...

跟踪哈希集中的所有渲染对象。 如果对象尚未呈现,则循环遍历每个属性并呈现对象。 如果对象已呈现,则仅呈现主键 (Guid)。

public class GuidRefJsonConverter : JsonConverter
{
public override bool CanRead { get { return false; } }
public override bool CanWrite { get { return true; } }
public override bool CanConvert(Type objectType)
{
return typeof(EntityBase).IsAssignableFrom(objectType);
}
private HashSet<EntityBase> serializedObjects = new HashSet<EntityBase>();
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
EntityBase eb = (EntityBase)value;
JObject jo = new JObject();
jo.Add("Guid", eb.Guid.ToString());
if (serializedObjects.Add(eb))
{
foreach (PropertyInfo prop in value.GetType().GetProperties())
{
if (prop.GetCustomAttribute<JsonIgnoreAttribute>() != null) continue;
if (prop.CanRead)
{
object propVal = prop.GetValue(value);
if (propVal != null && prop.Name!="Guid")
{
jo.Add(prop.Name, JToken.FromObject(propVal, serializer));
}
}
}
}
jo.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}

最后,我们只需要注册我们的 JsonConverter。 在 WebApiConfig.Register() 方法中,只需注册序列化程序。

var json = config.Formatters.JsonFormatter;
json.SerializerSettings.Converters=new List<JsonConverter>(){new GuidRefJsonConverter()};

这就做到了。 API 现在将仅使用主键序列化循环引用,RestKit 将选取该循环引用作为空的 Upsert,并正确映射其所有指针。

您正在寻找外键连接。这允许 RestKit 搜索具有现有标识符的托管对象,以便可以重用它们而不是创建新对象。

每个 ref 需要不同的对象,对象需要将 ref 值作为变量,变量应设置为唯一标识符,并且不同的对象应彼此具有关系。

相关内容

  • 没有找到相关文章

最新更新