Newtonsoft JsonConvert.SerializeObject ignoring JsonProperty if name is uppercase - c#

I want to be able to use the CamelCasePropertyNameContractResolver but override it for specific property names. For this, I use the JsonProperty attribute. This works fine except when the name that I choose is fully uppercase. Any ideas what's wrong or how to get around it?
In the example below, Bar is serialized to "BAR" when I don't use the CamelCasePropertyNameContractResolver, but is serialized to "bar" when I do use the resolver. Foo and CamelCaseProperty are serialized correctly in both scenarios.
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace ConsoleTester
{
class Program
{
static void Main(string[] args)
{
var foo = new FooBar {CamelCaseProperty = "test", Foo = "test", Bar = "test" };
var output = JsonConvert.SerializeObject(foo);
// output "CamelCaseProperty", "fOO", "BAR"
var output2 = JsonConvert.SerializeObject(foo, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() });
// output "camelCaseProperty", "fOO", "bar"
}
}
public class FooBar
{
public string CamelCaseProperty { get; set; }
[JsonProperty("fOO")]
public string Foo { get; set; }
[JsonProperty("BAR")]
public string Bar { get; set; }
}
}

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.

JsonProperty Attribute is not honoured when you use a ContractResolver.
What you can do to solve this issue is override the ContractResolver:
public class MyResolver : CamelCasePropertyNamesContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if(member.GetCustomAttribute<JsonPropertyAttribute>() is JsonPropertyAttribute jsonProperty)
{
property.PropertyName = jsonProperty.PropertyName;
}
return property;
}
}
And use your Resolver:
var output2 = JsonConvert.SerializeObject(foo, new JsonSerializerSettings { ContractResolver = new MyResolver() });

Related

ignore newton Json's JsonProperty on the fly?

We have some web API and some clients to consume the output.
One api return this:
public class InstrumentInfoV11 : InstrumentInfoBase
{
[JsonProperty("InstrumentType")]
public string InstrumentTypeCode { get; set; }
}
basically our API output property InstrumentType and we want our c# client to have a property called InstrumentTypeCode instead. JsonProperty did work and the c# property is populated.
However, when we try to output the result from the client:
InstrumentInfoV11 response = await Client.InstrumentInfoAsync(theRequest);
return JsonConvert.SerializeObject(response, Formatting.Indented);
The property InstrumentTypeCode becomes InstrumentType again
{
"InstrumentType": "X",
...
}
Is there a way to tell newton that when SerializeObject, it should ignore JsonProperty("InstrumentType") and when deSerializeObject, it should take it into consideration?
Usually serializers want to be able to store and reload the same data, so if you store something as X, it wants to read it as X, otherwise the assumption is that it can't do the job of loading data it wrote.
However, you could perhaps have two properties - allow either to read, and only ever write one; i.e.
// the real property
public string InstrumentTypeCode { get; set; }
// conditional serialization
[Browsable(false)]
public bool ShouldSerializeInstrumentTypeCode() => false;
// shim property
[Browsable(false)]
public string InstrumentType {
get => InstrumentTypeCode;
set => InstrumentTypeCode = value;
}
You could use a Custom Contract Resolver for the purpose. For example,
public class IgnorePropertyNameContractResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> list = base.CreateProperties(type, memberSerialization);
foreach (JsonProperty prop in list)
{
prop.PropertyName = prop.UnderlyingName;
}
return list;
}
}
You could use Deserialize using Json Property Name
var jsonResponse = "{'InstrumentType':'abc'}";
var instance = JsonConvert.DeserializeObject<InstrumentInfoV11>(jsonResponse);
And Serialize ignoring the Json Property Name
JsonSerializerSettings settings = new JsonSerializerSettings{ContractResolver = new IgnorePropertyNameContractResolver()};
var serialized = JsonConvert.SerializeObject(instance,settings);
Output
{"InstrumentTypeCode":"abc"}

How to exclude a property from being serialized in System.Text.Json.JsonSerializer.Serialize() using a JsonConverter

I want to be able to exclude a property when serializing using System.Text.Json.JsonSerializer. I don't want to use a JsonIgnore attribute everywhere I want to do this. I would like to be able to define the properties I want to exclude during serialization only, via some kind of Fluent API, which currently does not exist.
The only option I was able to find is to define a JsonConverter and add it to the list of Converters on the JsonSerializerOptions that I pass to the Serialize() method like so:
var options = new JsonSerializerOptions();
options.Converters.Add(new BookConverter());
json = JsonSerializer.Serialize(book, options);
In the JsonConverter I would have to write the entire JSON representation myself using a Utf8JsonWriter, excluding the property I don't want to serialize. This is a lot of work to just be able to exclude a property. While the JsonConverter is a great extensibility feature from the .NET team, its just too low-level for my use case. Does anyone know of any other way to acheive the exclusion of the property without having to write out the JSON representation myself?
I don't want to have to do the following:
Use an attribute, or dynamically add an attribute at runtime
Change the access modifier of the property to something like private or protected
Use a 3rd party library, as my issue is solvable if I use Json.NET.
Example:
class Program
{
void Main()
{
// We want to serialize Book but to ignore the Author property
var book = new Book() { Id = 1, Name = "Calculus", Author = new Author() };
var json = JsonSerializer.Serialize(book);
// Default serialization, we get this:
// json = { "Id": 1, "Name": "Calculus", "Author": {} }
// Add our custom converter to options and pass it to the Serialize() method
var options = new JsonSerializerOptions();
options.Converters.Add(new BookConverter());
json = JsonSerializer.Serialize(book, options);
// I want to get this:
// json = { Id: 1, Name: "Calculus" }
}
}
public class Author { }
public class Book
{
public int Id { get; set; }
public string Name { get; set; }
public Author Author { get; set; }
}
public class BookConverter : JsonConverter<Book>
{
public override Book Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
// Use default implementation when deserializing (reading)
return JsonSerializer.Deserialize<Book>(ref reader, options);
}
public override void Write(Utf8JsonWriter writer, Book value, JsonSerializerOptions options)
{
// Serializing. Here we have to write the JSON representation ourselves
writer.WriteStartObject();
writer.WriteNumber("Id", value.Id);
writer.WriteString("Name", value.Name);
// Don't write Author so we can exclude it
writer.WriteEndObject();
}
}
Option 1 - Cast to Interface
Extract interface which describes structure of desired object.
public interface IBook
{
public int Id { get; set; }
public string Name { get; set; }
}
Implement it on the original class class Book : IBook
Use the follow overload of string Serialize(object value, Type inputType, JsonSerializerOptions options = null);
json = JsonSerializer.Serialize(book, typeof(IBook), options);
If you're serializing array of Books (plural), you'll need to pass typeof(IEnumerable<IBook>) as an argument.
Option 2 - Use AutoMapper
This is useful if you don't have access to the original Book class.
Create LiteBook class:
public class LiteBook
{
public int Id { get; set; }
public string Name { get; set; }
}
Create mapping configuration:
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<Book, LiteBook>();
});
Map it and serialize
json = JsonSerializer.Serialize(new Mapper(config).Map<LiteBook>(book), options)
So I happened to stumble upon an article that demonstrates how to use the JsonDocument object in the new System.Text.Json namespace and it is the next best thing to a Fluent API. Here is how this question can be solved.
The BookConverter.Write() method:
public override void Write(Utf8JsonWriter writer, Book value, JsonSerializerOptions options)
{
writer.WriteStartObject();
using (JsonDocument document = JsonDocument.Parse(JsonSerializer.Serialize(value)))
{
foreach (var property in document.RootElement.EnumerateObject())
{
if (property.Name != "Author")
property.WriteTo(writer);
}
}
writer.WriteEndObject();
}
You can simply ignore a property like this:
public class Book
{
public int Id { get; set; }
public string Name { get; set; }
[JsonIgnore]
public Author Author { get; set; }
}
reference: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-ignore-properties?pivots=dotnet-6-0
You can try to use the following method:
public static object ConvertToObjectWithoutListedProperties<T>(
this T objectToTransform,
string[] propertiesToIgnore)
{
var type = objectToTransform.GetType();
var returnClass = new ExpandoObject() as IDictionary<string, object>;
foreach (var propertyInfo in type.GetProperties())
if (!propertiesToIgnore.Contains(propertyInfo.Name))
returnClass.Add(propertyInfo.Name,
propertyInfo.GetValue(objectToTransform));
return returnClass;
}
Credits: "Remove the null property from object"
.Net 7 made it possible to more flexibly and dynamically control which properties get serialized. See here for the official blog post:
https://devblogs.microsoft.com/dotnet/system-text-json-in-dotnet-7/#example-conditional-serialization

Serializing single instance to multiple JSON strings

Given the following class:
public class Config {
public string Property1 {get; set;} = "foo";
public string Property2 {get; set;} = "bar";
public string Property3 {get; set;} = "baz";
public string Property4 {get; set;} = "baz1";
}
I want to serialize an instance of this class into two separate JSON strings. Some of the properties should go into the first JSON string:
{
"Property1": "foo",
"Property2": "bar"
}
while the rest of the properties should go into the other JSON string:
{
"Property3": "baz",
"Property4": "baz1"
}
The division of properties is always the same, and properties will go either to one or the other.
(I can deserialize the two JSON strings back into a single object using JObject.Merge.)
Currently, I am writing to a pair of JObject instances, but that is a maintenance nightmare (json["Property1"] = x.Property1; json["Property2"] = x.Property2; etc.).
How can I do this in a way which is easier to maintain?
Making life complicated for no reason but whatever. Here is one way to solve the problem:
Create your own attribute class. Can be either one class per serialization "batch" or one class with the name of the serialization. For example, the name of the attribute class could be JsonSerializationBatchAttribute
Decorate your data members with that attribute like this:
public class Config {
[JsonSerializationBatch("1")]
public string Property1 {get; set;} = "foo";
[JsonSerializationBatch("1")]
public string Property2 {get; set;} = "bar";
[JsonSerializationBatch("2")]
public string Property3 {get; set;} = "baz";
[JsonSerializationBatch("2")]
public string Property4 {get; set;} = "baz1";
}
Then implement conditional serialization as described here:
https://www.newtonsoft.com/json/help/html/ConditionalProperties.htm
in the serialization function check if a property has JsonSerializationBatch attribute with proper string and ignore all properties that do not.
I would do this complex thing only if I would have many objects that need this type of serialization. If only one object requires such serialization then I would lean towards splitting class into more than one or using anonymous objects for serialization.
You could try using anonymous objects, like so:
var string1 = JsonConvert.SerializeObject(new {property1: config.Property1, property2: config.Property2});
var string2 = JsonConvert.SerializeObject(new {property3: config.Property3, property4: config.Property4});
PS: I'm assuming you are using newtonsoft.json if not, just replace the serialize method.
Hope to have helped!
I can write a class that inherits from Newtonsoft.Json.Serialization.DefaultContractResolver:
public class ConfigContractResolver : DefaultContractResolver {
private static readonly string[] source1Names = new[] {
nameof(Config.Property1),
nameof(Config.Property2)
};
public bool ForSource1 { get; set; } = true;
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) {
var ret = base.CreateProperties(type, memberSerialization);
var predicate = ForSource1 ?
x => source1Names.Contains(x.PropertyName) :
(Func<JsonProperty, bool>)(x => !source1Names.Contains(x.PropertyName));
ret = ret.Where(predicate).ToList();
return ret;
}
}
and serialize to both strings using an instance of ConfigContractResolver:
Config config = new Config();
// ...
var resolver = new ConfigContractResolver();
var serializationSettings = new JsonSerializerSettings {
ContractResolver = resolver
};
string forSource1 = JsonConvert.SerializeObject(config, serializationSettings);
// It would be nice to reuse the same contract resolver and settings objects
// but that doesn't seem to work -- https://github.com/JamesNK/Newtonsoft.Json/issues/2155
resolver = new ConfigContractResolver() {
ForSource1 = false
};
serializationSettings = new JsonSerializerSettings {
ContractResolver = resolver
};
resolver.ForSource1 = false;
string forSource2 = JsonConvert.SerializeObject(config, serializationSettings);
Source: IContractResolver example

Keep casing when serializing dictionaries

I have a Web Api project being configured like this:
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
However, I want dictionary keys casing to remain unchanged. is there any attribute in Newtonsoft.Json I can use to a class to denote that I want casing to remain unchanged during serialization?
public class SomeViewModel
{
public Dictionary<string, string> Data { get; set; }
}
There is not an attribute to do this, but you can do it by customizing the resolver.
I see that you are already using a CamelCasePropertyNamesContractResolver. If you derive a new resolver class from that and override the CreateDictionaryContract() method, you can provide a substitute DictionaryKeyResolver function that does not change the key names.
Here is the code you would need:
class CamelCaseExceptDictionaryKeysResolver : CamelCasePropertyNamesContractResolver
{
protected override JsonDictionaryContract CreateDictionaryContract(Type objectType)
{
JsonDictionaryContract contract = base.CreateDictionaryContract(objectType);
contract.DictionaryKeyResolver = propertyName => propertyName;
return contract;
}
}
Demo:
class Program
{
static void Main(string[] args)
{
Foo foo = new Foo
{
AnIntegerProperty = 42,
HTMLString = "<html></html>",
Dictionary = new Dictionary<string, string>
{
{ "WHIZbang", "1" },
{ "FOO", "2" },
{ "Bar", "3" },
}
};
JsonSerializerSettings settings = new JsonSerializerSettings
{
ContractResolver = new CamelCaseExceptDictionaryKeysResolver(),
Formatting = Formatting.Indented
};
string json = JsonConvert.SerializeObject(foo, settings);
Console.WriteLine(json);
}
}
class Foo
{
public int AnIntegerProperty { get; set; }
public string HTMLString { get; set; }
public Dictionary<string, string> Dictionary { get; set; }
}
Here is the output from the above. Notice that all of the class property names are camel-cased, but the dictionary keys have retained their original casing.
{
"anIntegerProperty": 42,
"htmlString": "<html></html>",
"dictionary": {
"WHIZbang": "1",
"FOO": "2",
"Bar": "3"
}
}
Json.NET 9.0.1 introduced the NamingStrategy class hierarchy to handle this sort of issue. It extracts the logic for algorithmic remapping of property names from the contract resolver to a separate, lightweight class that allows for control of whether dictionary keys, explicitly specified property names, and extension data names (in 10.0.1) are remapped.
By using DefaultContractResolver and setting NamingStrategy to an instance of CamelCaseNamingStrategy you can generate JSON with camel-cased property names and unmodified dictionary keys by setting it in JsonSerializerSettings.ContractResolver:
var resolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy
{
ProcessDictionaryKeys = false,
OverrideSpecifiedNames = true
}
};
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = resolver;
Notes:
The current implementation of CamelCasePropertyNamesContractResolver also specifies that .Net members with explicitly specified property names (e.g. ones where JsonPropertyAttribute.PropertyName has been set) should have their names remapped:
public CamelCasePropertyNamesContractResolver()
{
NamingStrategy = new CamelCaseNamingStrategy
{
ProcessDictionaryKeys = true,
OverrideSpecifiedNames = true
};
}
The above resolver preserves this behavior. If you don't want this, set OverrideSpecifiedNames = false.
Json.NET has several built-in naming strategies including:
CamelCaseNamingStrategy. A camel case naming strategy that contains the name-remapping logic formerly embedded in CamelCasePropertyNamesContractResolver.
SnakeCaseNamingStrategy. A snake case naming strategy.
DefaultNamingStrategy. The default naming strategy. Property names and dictionary keys are unchanged.
Or, you can create your own by inheriting from the abstract base class NamingStrategy.
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.
That is a very nice answer. But why not just override the ResolveDictionaryKey?
class CamelCaseExceptDictionaryResolver : CamelCasePropertyNamesContractResolver
{
#region Overrides of DefaultContractResolver
protected override string ResolveDictionaryKey(string dictionaryKey)
{
return dictionaryKey;
}
#endregion
}
The selected answer is perfect but I guess by the time I'm typing this, the contract resolver must change to something like this because DictionaryKeyResolver doesn't exists anymore :)
public class CamelCaseExceptDictionaryKeysResolver : CamelCasePropertyNamesContractResolver
{
protected override JsonDictionaryContract CreateDictionaryContract(Type objectType)
{
JsonDictionaryContract contract = base.CreateDictionaryContract(objectType);
contract.PropertyNameResolver = propertyName => propertyName;
return contract;
}
}

C# JSON.NET convention that follows Ruby property naming conventions?

I am using http://json.codeplex.com/ and I am talking to a Ruby based Rest API. Problem is that most of the properties have a ruby underscore naming convention. I am wondering if anyone knows of a way so that I can avoid having to Add lots of JsonProperty.
For example I want to avoid adding the JsonProperty attribute and have a convention built into the serializer settings so that it knows to try and map properties with an underscore in the to the .NET naming convention :)
public class Member
{
[JsonProperty(PropertyName = "avatar_url")]
public string AvatarUrl { get; set; }
[JsonProperty(PropertyName = "twitter_screen_name")]
public string TwitterScreenName { get; set; }
[JsonProperty(PropertyName = "website_url")]
public string WebSiteUrl { get; set; }
}
Update - September 2016:
Json.NET 9.0.1 has SnakeCaseNamingStrategy. You can use that to have twitter_screen_name style properties automatically.
Inherit from DefaultContractResolver and override ResolvePropertyName to format property names as you'd like.
CamelCasePropertyNamesContractResolver does a similar global change to property names.
Read this : http://nyqui.st/json-net-newtonsoft-json-lowercase-keys
public class UnderscoreMappingResolver : DefaultContractResolver
{
protected override string ResolvePropertyName(string propertyName)
{
return System.Text.RegularExpressions.Regex.Replace(
propertyName, #"([A-Z])([A-Z][a-z])|([a-z0-9])([A-Z])", "$1$3_$2$4").ToLower();
}
}
As of version 9, a new naming strategy property exists to do this, and it has a built-in SnakeCaseNamingStrategy class. Use the code below and register contractResolver as SerializerSettings.ContractResolver.
var contractResolver = new DefaultContractResolver();
contractResolver.NamingStrategy = new SnakeCaseNamingStrategy();
That class does not include dictionaries by default, and it does not override any manually-set property values. Those are the two parameters that can be passed in the overload:
// true parameter forces handling of dictionaries
// false prevents the serializer from changing anything manually set by an attribute
contractResolver.NamingStrategy = new SnakeCaseNamingStrategy(true, false);
This one worked for me
var settings = new JsonSerializerSettings
{
ContractResolver = new PascalCaseToUnderscoreContractResolver()
};
var rawJson = "{ test_property:'test' }"
var myObject = JsonConvert.DeserializeObject<MyObjectType>(rawJson, settings);
Using Humanizer function "Underscore"
https://www.nuget.org/packages/Humanizer/1.37.7
http://humanizr.net/#underscore
public class PascalCaseToUnderscoreContractResolver : DefaultContractResolver
{
protected override string ResolvePropertyName(string propertyName) => propertyName.Underscore();
}
MyObjectType class
public Class MyObjectType
{
public string TestProperty {get;set;}
}

Categories

Resources