Add Multiple Contract Resolver in Newtonsoft.Json

后端 未结 3 454
名媛妹妹
名媛妹妹 2020-12-17 15:16

Blueprint for data structure:

public class Movie
{
    public string Name { get; set; }
}

Using Newtonsoft.Json, I have the following confi

相关标签:
3条回答
  • 2020-12-17 15:23

    Here is an alternative. Rather than using two ContractResolvers, you can use NamingStrategy instead of CamelCasePropertyNamesContractResolver.

    var settings = new JsonSerializerSettings()
    {
        ContractResolver = new NullToEmptyStringResolver(){NamingStrategy = new CamelCaseNamingStrategy()}
    };
    

    This is the similar @BrianRogers's second approach. I just didn't hard code the setting to NullToEmptyStringResolver class.

    0 讨论(0)
  • 2020-12-17 15:33

    I find it's a much better idea to create a composite-contract-resolver. This is what I use in my projects:

    public class CompositeContractResolver : IContractResolver, IEnumerable<IContractResolver>
    {
        private readonly IList<IContractResolver> _contractResolvers = new List<IContractResolver>();
    
        public JsonContract ResolveContract(Type type)
        {
            return
                _contractResolvers
                    .Select(x => x.ResolveContract(type))
                    .FirstOrDefault(Conditional.IsNotNull);
        }
    
        public void Add([NotNull] IContractResolver contractResolver)
        {
            if (contractResolver == null) throw new ArgumentNullException(nameof(contractResolver));
            _contractResolvers.Add(contractResolver);
        }
    
        public IEnumerator<IContractResolver> GetEnumerator()
        {
            return _contractResolvers.GetEnumerator();
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
    

    I then use it like this:

    Settings = new JsonSerializerSettings
    {
        ContractResolver = new CompositeContractResolver
        {
            new InterfaceContractResolver<ISomething>(),
            new DefaultContractResolver()
        }
    }
    

    where my custom contract-resolvers return a null contract so the composite one can fall through the default one if there is no match.

    public class InterfaceContractResolver<T> : DefaultContractResolver
    {
        public InterfaceContractResolver()
        {
            if (!typeof(T).IsInterface) throw new InvalidOperationException("T must be an interface.");
        }
    
        public override JsonContract ResolveContract(Type type)
        {
            return 
                typeof(T).IsAssignableFrom(type) 
                    ? base.ResolveContract(typeof(T)) 
                    : default;
        }
    
        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            return
                typeof(T).IsAssignableFrom(type)
                    ? base.CreateProperties(typeof(T), memberSerialization)
                    : default;
        }
    }
    
    0 讨论(0)
  • 2020-12-17 15:40

    Json.Net does not allow more than one contract resolver at a time, so you will need a way to combine their behaviors. I'm assuming that NullToEmptyStringResolver is a custom resolver which inherits from Json.Net's DefaultContractResolver class. If so, one simple way to achieve your desired result is to make the NullToEmptyStringResolver inherit from CamelCasePropertyNamesContractResolver instead.

    public class NullToEmptyStringResolver : CamelCasePropertyNamesContractResolver
    {
        ...
    }
    

    If you don't like that approach, another idea is to add the camel casing behavior to yourNullToEmptyStringResolver. If you take a look at how CamelCasePropertyNamesContractResolver is implemented in the source code, you'll see this is as simple as setting the NamingStrategy in the constructor (assuming you are using Json.Net 9.0.1 or later). You can add this same code to the constructor of yourNullToEmptyStringResolver.

    public class NullToEmptyStringResolver : DefaultContractResolver
    {
        public NullToEmptyStringResolver() : base()
        {
            NamingStrategy = new CamelCaseNamingStrategy
            {
                ProcessDictionaryKeys = true,
                OverrideSpecifiedNames = true
            };
        }
    
        ...
    }
    
    0 讨论(0)
提交回复
热议问题