The reason you are seeing this is that CamelCasePropertyNamesContractResolver
is intentionally designed to override the casing of dictionary keys and explicitly set property names, as can be see from the reference source:
public CamelCasePropertyNamesContractResolver()
{
NamingStrategy = new CamelCaseNamingStrategy
{
ProcessDictionaryKeys = true,
OverrideSpecifiedNames = true
};
}
If you don't want that, you have several options to prevent casing of explicit names without creating your own custom contract resolver type.
Firstly, you could serialize using a DefaultContractResolver
with NamingStrategy = new CamelCaseNamingStrategy()
:
var settings = new JsonSerializerSettings
{
ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() }
};
var output2 = JsonConvert.SerializeObject(foo, settings);
This leaves CamelCaseNamingStrategy.OverrideSpecifiedNames
at its default value of false
.
Secondly, if you don't have access to the contract resolver of your framework, you could set JsonPropertyAttribute.NamingStrategyType = typeof(DefaultNamingStrategy)
on specific properties, like so:
public class FooBar
{
public string CamelCaseProperty { get; set; }
[JsonProperty("fOO")]
public string Foo { get; set; }
[JsonProperty("BAR", NamingStrategyType = typeof(DefaultNamingStrategy))]
public string Bar { get; set; }
}
Thirdly, if you want your entire object to ignore the naming strategy of the current contract resolver, you can apply [JsonObject(NamingStrategyType = typeof(TNamingStrategy))]
to your object:
[JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
public class FooBar
{
public string CamelCaseProperty { get; set; }
[JsonProperty("fOO")]
public string Foo { get; set; }
[JsonProperty("BAR")]
public string Bar { get; set; }
}
Notes:
While it is also possible to modify the NamingStrategy
of an instance of CamelCasePropertyNamesContractResolver
, since the latter shares contract information globally across all instances of each type, this can lead to unexpected side-effects if your application tries to use multiple instances of CamelCasePropertyNamesContractResolver
. No such problem exists with DefaultContractResolver
, so it is safer to use when any customization of casing logic is required.
When using or subclassing DefaultContractResolver
, you may want to cache the contract resolver for best performance, since it does not share contract information globally across all instances of each type.
I don't know why Json.NET's camel case resolver is designed to override specified names, it may be for historical reasons.
Naming strategies were first introduced in Json.NET 9.0.1 so this answer works only for that version and later.