手短に言えば、はい、それが出発点として適切な場所です。これが私が最終的に得たものです(今のところ):
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 を検索、変更、および複製して、 my Id
andを表すこともできName
ます。
私のasp.net Web APIでは、このMyContractResolverをJsonFormatter.SerializerSettingsのContractResolverとして設定します。
それで、シリアル化のために私を修正しました。逆シリアル化のために、PropertyInfo とオブジェクトを格納するカスタム ChangeSet オブジェクトがあります。次に、逆シリアル化中に Id を保持し、後でデータ ストアから 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;
}
さしあたって、クリーン エンティティと動的シリアライゼーションのすべての悲惨な詳細は悲しいことに 2 つの場所にカプセル化されていますが、シリアライザーからデータ ソースにアクセスしたくないので、仕方がありませんでした。