2016-10-02 68 views
2

我试图为Json.NET创建一个自定义的ValueProvider,它将跳过序列化所有对象,并将只返回代表其主键的类型Guid的属性一个参考)。Json.NET自定义ValueProvider将对象转换为Guid

例子:

jsonData: { 
    myObject: { 
     id: "23e23-2gg5-6y666556-y6yg33", 
     property2: "" 
    } 
} 

应该改为:

jsonData: { 
    myObjectId: "23e23-2gg5-6y666556-y6yg33" 
} 

这是我写到目前为止代码。我非常接近使其工作,但在我的CustomValueProvider我似乎无法获得对象值。我怎样才能做到这一点?

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 
    }; 

回答

3

您想要将嵌套对象内的"Id"值提升为父对象。为此,您需要将两个价值提供者链接在一起:

  • 获取成员值的外部值提供程序。
  • 获取成员的Id的值的内部值提供程序。

下做到这一点:

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; 
    } 
} 

注意,使用内部合同解析器。这可以防止递归调用递归类型的问题。

您可能还想要考虑处理具有ID的对象的集合或具有ID的对象的字典。例如在下面的对象时,List<MyObject>Dictionary<string, MyObject>属性将暴露的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; } 
} 
+1

嗯...我没想到这是如此艰难。非常感谢,你救了我。 – tocqueville