Search code examples
c#jsonjsonserializer

JsonSerializerSettings to change case of property name but not name of property's property


I am using below settings for camel casing of my class property.

JsonSerializerSettings settings = new JsonSerializerSettings()
        {
            ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
        };

Some of the property in the object are of some other class type. I do not want to change case of those properties.

Eg:

Public Class CaseToChange
{
    public string StringProperty{get;set;} //Change to camelCase
    public SomeOtherType OtherTypeProperty{get;set;} //Change name of this to camelCase but not property name of "SomeOtherType"

}

How to achieve this with JsonSerializerSettings?


Solution

  • If you can modify your types to add Json.NET serialization attributes, the easiest thing to do would be to add [JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))] to your CaseToChange type:

    [JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
    public class CaseToChange
    {
        public string StringProperty { get; set; } //Change to camelCase
        public SomeOtherType OtherTypeProperty { get; set; } //Change name of this to camelCase but not property name of "SomeOtherType"
    }
    

    (Or, if you are using a version of Json.NET earlier than 9.0.1, add [JsonProperty("camelCaseName")] to each property as in this answer.)

    If you cannot modify the type and must camel-case the properties of CaseToChange only through serializer settings, you can create a custom contract resolver that returns camel-cased names for CaseToChange and unmodified names for other types. The following does the trick:

    public class OverrideContractResolver : ContractResolverDecorator
    {
        readonly Dictionary<Type, IContractResolver> overrides;
    
        public OverrideContractResolver(IEnumerable<KeyValuePair<Type, IContractResolver>> overrides, IContractResolver baseResolver)
            : base(baseResolver)
        {
            if (overrides == null)
                throw new ArgumentNullException();
            this.overrides = overrides.ToDictionary(p => p.Key, p => p.Value);
        }
    
        public override JsonContract ResolveContract(Type type)
        {
            IContractResolver resolver;
            if (overrides.TryGetValue(type, out resolver))
                return resolver.ResolveContract(type);
            return base.ResolveContract(type);
        }
    }
    
    public class ContractResolverDecorator : IContractResolver
    {
        readonly IContractResolver baseResolver;
    
        public ContractResolverDecorator(IContractResolver baseResolver)
        {
            if (baseResolver == null)
                throw new ArgumentNullException();
            this.baseResolver = baseResolver;
        }
    
        #region IContractResolver Members
    
        public virtual JsonContract ResolveContract(Type type)
        {
            return baseResolver.ResolveContract(type);
        }
    
        #endregion
    }
    

    Then serialize with settings as follows:

    var settings = new JsonSerializerSettings
    {
        ContractResolver =
            new OverrideContractResolver(
                new Dictionary<Type, IContractResolver> { { typeof(CaseToChange), new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver() } },
                new Newtonsoft.Json.Serialization.DefaultContractResolver()),
    };
    

    And the resulting JSON will look like:

    {
      "stringProperty": "string property",
      "otherTypeProperty": {
        "FooProperty": "foo",
        "BarProperty": 101
      }
    }
    

    Sample fiddle.

    For optimal performance you may want to cache instances of the contract resolver.