简短的回答是肯定的,这将是合适的起点。这是我最终得到的(现在):
public class MyContractResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
foreach (var pi in type.GetProperties().Where(pi => typeof (Entity).IsAssignableFrom(pi.DeclaringType) && Attribute.IsDefined((MemberInfo) pi, typeof(IdNameMemberAttribute))))
{
properties.Add(CreateReferenceProperty(pi, Reflect.GetProperty<Entity>(e => e.Id)));
properties.Add(CreateReferenceProperty(pi, Reflect.GetProperty<Entity>(e => e.Name)));
}
return properties;
}
private JsonProperty CreateReferenceProperty(PropertyInfo reference, PropertyInfo referenceMember)
{
var jsonProperty = base.CreateProperty(reference, MemberSerialization.OptOut);
jsonProperty.PropertyName += referenceMember.Name;
jsonProperty.ValueProvider = new ReferencedValueProvider(reference, referenceMember);
jsonProperty.Writable = false;
return jsonProperty;
}
}
IdNameMemberAttribute
只是一个空属性,我用它来注释我想要序列化的引用属性。重要的是,我不会使用 Json.NET 将识别并用于生成 JsonProperty 的任何内容对其进行注释。这样我就不会从我的 CreateProperties 中得到一个重复的 JsonProperty。
或者,我可以从 DataMemberAttribute 派生并查找、修改和克隆 JsonProperty 来表示我的Id
and Name
。
然后,对于我的 asp.net web api,我将此 MyContractResolver 设置为 JsonFormatter.SerializerSettings 的 ContractResolver。
所以这让我为序列化做好了准备。对于反序列化,我有一个自定义 ChangeSet 对象,我在其中存储 PropertyInfo 和对象。然后,在反序列化期间,我确保保留 Id,然后从我的数据存储中解析它们,在我的情况下,使用自定义 ActionFilter 访问数据存储会话。
这是我的序列化的精髓:
var jsonSource = streamReader.ReadToEnd();
var deserializedObject = JsonConvert.DeserializeObject(jsonSource, type, SerializerSettings);
var changeSet = deserializedObject as PropertyChangeSet;
if (changeSet != null)
{
var jsonChange = JObject.Parse(jsonSource)["Change"].Cast<JProperty>().ToArray();
IDictionary<string, int> references = jsonChange.Where(IsReferenceId).ToDictionary(t => t.Name.Substring(0, t.Name.Length - 2), t => t.Value.ToObject<int>());
changeSet.References = references;
var properties = jsonChange.Where(jp => !IsReferenceId(jp)).Select(t => t.Name).ToList();
changeSet.Primitives = properties;
}
而且,我的干净实体和动态序列化的所有血腥细节都被封装了,遗憾的是在两个地方,但由于我不想从序列化程序访问我的数据源,所以没有帮助。