【问题标题】:Json.NET Custom ValueProvider to convert Objects into GuidJson.NET 自定义 ValueProvider 将对象转换为 Guid
【发布时间】:2016-10-02 11:54:35
【问题描述】:

我正在尝试为 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
    };

【问题讨论】:

    标签: c# json asp.net-mvc json.net


    【解决方案1】:

    您希望将嵌套对象内部的 "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; }
    }
    

    【讨论】:

    • 嗯...我没想到这会这么难。非常感谢,你救了我。
    猜你喜欢
    • 2011-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-01
    • 2014-01-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多