Json.NET自定义ValueProvider将对象转换为Guid [英] Json.NET Custom ValueProvider to convert Objects into Guid
问题描述
我正在尝试为Json.NET创建一个自定义ValueProvider,它将跳过序列化所有对象的过程,而只是返回Guid类型的属性来表示其主键(作为参考).
I'm trying to create a custom ValueProvider for Json.NET that will skip serializing all the objects, and will just return a property of type Guid representing their primary Key instead (as a reference).
示例:
jsonData: {
myObject: {
id: "23e23-2gg5-6y666556-y6yg33",
property2: ""
}
}
应成为:
jsonData: {
myObjectId: "23e23-2gg5-6y666556-y6yg33"
}
这是我到目前为止编写的代码.我非常接近使其工作,但是在我的CustomValueProvider
中,我似乎无法获取对象值.我该怎么办?
This is the code I wrote so far. I'm very close to make it work, but in my CustomValueProvider
I don't seem to be able to get the object values. How can I do that?
private class CustomValueProvider : IValueProvider
{
private readonly MemberInfo _member;
public CustomValueProvider(MemberInfo member)
{
_member = member;
}
public void SetValue(object target, object value)
{
throw new NotImplementedException();
}
public object GetValue(object target)
{
return // WHAT HERE??
}
}
private class CustomResolver : CamelCasePropertyNamesContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var jsonProperty = base.CreateProperty(member, memberSerialization);
if (jsonProperty.PropertyType.IsClass && jsonProperty.PropertyType != typeof(string))
{
jsonProperty = new JsonProperty
{
PropertyName = member.Name.ToFirstCharLower() + "Id",
Readable = true,
ShouldSerialize = value => true,
PropertyType = typeof(Guid),
ValueProvider = new CustomValueProvider(member)
};
}
return jsonProperty;
}
}
private static readonly JsonSerializerSettings JsonSettings = new JsonSerializerSettings
{
ContractResolver = new CustomResolver(),
Formatting = Formatting.Indented
};
推荐答案
您要将"Id"
值从嵌套对象内部提升为父对象.为此,您需要将两个价值提供者链接在一起:
You want to promote the "Id"
value from inside the nested object to the parent object. To do that, you're going to need to chain together two value providers:
- 外部价值提供者,用于获取成员的价值.
- 内部值提供程序,用于获取成员的
Id
的值.
- An outer value provider to get the value of the member.
- An inner value provider to get the value of the
Id
of the member.
以下操作是这样的:
class NestedValueProvider : IValueProvider
{
readonly IValueProvider outerProvider;
readonly IValueProvider innerProvider;
public NestedValueProvider(IValueProvider outerProvider, IValueProvider innerProvider)
{
if (outerProvider == null || innerProvider == null)
throw new ArgumentNullException();
this.outerProvider = outerProvider;
this.innerProvider = innerProvider;
}
public void SetValue(object target, object value)
{
throw new NotImplementedException();
}
public object GetValue(object target)
{
var innerTarget = outerProvider.GetValue(target);
if (innerTarget == null)
return null;
return innerProvider.GetValue(innerTarget);
}
}
class CustomResolver : CamelCasePropertyNamesContractResolver
{
// Using an inner resolver prevents difficulties with recursion.
readonly CamelCasePropertyNamesContractResolver innerResolver = new CamelCasePropertyNamesContractResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var jsonProperty = base.CreateProperty(member, memberSerialization);
if (!jsonProperty.PropertyType.IsPrimitive && jsonProperty.PropertyType != typeof(string) && jsonProperty.Readable)
{
var innerContract = innerResolver.ResolveContract(jsonProperty.PropertyType);
if (innerContract is JsonObjectContract)
{
var objectContract = (JsonObjectContract)innerContract;
var idProperty = objectContract.Properties.GetClosestMatchProperty(ResolvePropertyName("Id"));
if (idProperty != null && idProperty.Readable && (innerResolver.ResolveContract(idProperty.PropertyType) is JsonPrimitiveContract))
{
jsonProperty = new JsonProperty
{
PropertyName = ResolvePropertyName(member.Name + "Id"),
Readable = true,
PropertyType = idProperty.PropertyType,
ValueProvider = new NestedValueProvider(jsonProperty.ValueProvider, idProperty.ValueProvider),
};
}
}
// Possibly handle innerContract is JsonArrayContract?
// Possibly handle innerContract is JsonDictionaryConract?
}
return jsonProperty;
}
}
请注意使用内部合同解析器.这样可以防止递归调用递归类型时出现问题.
Note the use of an inner contract resolver. This prevents problems with recursive calls for recursive types.
您可能还想考虑处理具有ID的对象的集合或具有ID的对象的字典.例如,在以下对象中,List<MyObject>
和Dictionary<string, MyObject>
属性将公开MyObject
的内容:
You might also want to consider handling collections of objects with IDs, or dictionaries of objects with IDs. For instance in the following object, the List<MyObject>
and Dictionary<string, MyObject>
properties will expose contents of MyObject
:
public class RootObject
{
// Correctly not remapped
public string StringValue { get; set; }
// Correctly remaps to a GUID.
public MyObject MyObject { get; set; }
// Remap to a List<Guid> ?
public List<MyObject> MyObjectList { get; set; }
// Remap to a Dictionary<string, Guid> ?
public Dictionary<string, MyObject> MyObjectDictionary { get; set; }
}
public class MyObject
{
public Guid Id { get; set; }
public string Property2 { get; set; }
}
这篇关于Json.NET自定义ValueProvider将对象转换为Guid的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!