我有一个使用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",
}
答案 0 :(得分:5)
答案不在于RestKit,而在于您的JSON.Net序列化。以下是问题:
因此,为了实现这一点,我们需要使用WCF引用将对象从我们的服务层转移到我们的API层,然后仅使用对象的主键作为参考来创建我们自己的json序列化,而不是$ WCF使用的id $ ref crap。
所以,这里有详细信息。
首先,您将获得$ ref $ id,因为您正在调用WCF服务,其中的类使用[DataContract(IsReference=true)]
属性进行修饰。 JSON.Net序列化程序将读取此属性并创建$ id,$ ref引用,如果您还没有用[JsonObject(IsReference=false)]
修饰类。您需要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。所以,这是逻辑......
跟踪HashSet中的所有渲染对象。如果尚未渲染对象,则循环遍历每个属性并渲染对象。如果对象已被渲染,则只渲染主键(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选取,并将正确映射其所有指针。
答案 1 :(得分:0)
您正在寻找foreign key connections。这允许RestKit使用现有标识符搜索托管对象,以便可以重用它们而不是创建新对象。
每个ref需要不同的对象,对象需要将ref值作为变量,变量应该设置为唯一标识符,不同的对象应该相互关联。