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

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;}
}

Related

How to Override a Default JsonConverter (specified in an attribute)

I would like the following Author type to have a default JsonConverter, and be able to override it at runtime.
[JsonConverter(typeof(BaseJsonConverter))]
public class Author
{
// The ID of an author entity in the application.
public int ID { set; get; }
// The ID of an Author entity in its source.
public string SourceID { set; set; }
}
I used the following code to override the default converter (i.e., BaseJsonConverter).
public class AlternativeConverter : BaseJsonConverter
{ // the serializer implementation is removed for clarity. }
// Deserialize using AlternativeConverter:
var author = JsonConvert.DeserializeObject<Author>(jsonString, new AlternativeConverter());
Question
Using the above call, the AlternativeConverter is first constructed; however, then an instance of BaseJsonConverter is initialized and used for deserialization. So, the AlternativeConverter is never used.
Executable example: https://dotnetfiddle.net/l0bgYO
Use case
The application is to convert different JSON objects, obtained from different sources, to a common C# type. Commonly data comes from a source for that we define the default converter (i.e., BaseJsonConverter), and for data coming from other sources, we define different converters per each.
Background
I am aware of methods such as this one, and indeed I am using similar method partially. With ref to that article, I need to have different _propertyMappings depending on the source of input, because in my application attribute to property mapping is not one-to-one. For instance, I have the following JSON objects:
{
"id":123
}
// and
{
"id":"456"
}
where the first JSON object should be deserialized to:
author.ID = 123
author.SourceID = null
and the second JSON object should be deserialized as:
author.ID = 0
author.SourceID = "456"
You can use a custom ContractResolver to override a [JsonConverter] attribute programmatically. To solve your problem you could make a custom resolver like this:
public class CustomResolver : DefaultContractResolver
{
private Dictionary<Type, JsonConverter> Converters { get; set; }
public CustomResolver(Dictionary<Type, JsonConverter> converters)
{
Converters = converters;
}
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
JsonObjectContract contract = base.CreateObjectContract(objectType);
if (Converters.TryGetValue(objectType, out JsonConverter converter))
{
contract.Converter = converter;
}
return contract;
}
}
Then, when you wanted to use the AlternativeConverter in place of the BaseJsonConverter, you could use the custom resolver like this:
// map the `Author` type to the `AlternativeConverter`
var converters = new Dictionary<Type, JsonConverter>()
{
{ typeof(Author), new AlternativeConverter() }
};
// Create a resolver with the converter mapping and add it to the serializer settings
var settings = new JsonSerializerSettings
{
ContractResolver = new CustomResolver(converters)
};
// Use the settings when deserializing
var author = JsonConvert.DeserializeObject<Author>(jsonString, settings);
Demo Fiddle: https://dotnetfiddle.net/cu0igV
Of course, if all you're really doing with these converters is remapping properties to different names, you could just use a ContractResolver for that in the first place and get rid of the converters altogether. See Json.NET deserialize or serialize json string and map properties to different property names defined at runtime for more information on that approach.
I think you should try to use different JsonSerializerSettings instances for different data sources, with different Converters collections. And remove JsonConverter attributes from your classes.

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

Newtonsoft JsonConvert.SerializeObject ignoring JsonProperty if name is uppercase

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() });

Control Deserializing Json Properties via Attributes? [duplicate]

I have some data in a C# DataSet object. I can serialize it right now using a Json.net converter like this
DataSet data = new DataSet();
// do some work here to populate 'data'
string output = JsonConvert.SerializeObject(data);
However, this uses the property names from data when printing to the .json file. I would like to change the property names to be something different (say, change 'foo' to 'bar').
In the Json.net documentation, under 'Serializing and Deserializing JSON' → 'Serialization Attributes' it says "JsonPropertyAttribute... allows the name to be customized". But there is no example. Does anyone know how to use a JsonPropertyAttribute to change the property name to something else?
(Direct link to documentation)
Json.net's documentation seems to be sparse. If you have a great example I'll try to get it added to the official documentation.
Thanks!
You could decorate the property you wish controlling its name with the [JsonProperty] attribute which allows you to specify a different name:
using Newtonsoft.Json;
// ...
[JsonProperty(PropertyName = "FooBar")]
public string Foo { get; set; }
Documentation: Serialization Attributes
If you don't have access to the classes to change the properties, or don't want to always use the same rename property, renaming can also be done by creating a custom resolver.
For example, if you have a class called MyCustomObject, that has a property called LongPropertyName, you can use a custom resolver like this…
public class CustomDataContractResolver : DefaultContractResolver
{
public static readonly CustomDataContractResolver Instance = new CustomDataContractResolver ();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (property.DeclaringType == typeof(MyCustomObject))
{
if (property.PropertyName.Equals("LongPropertyName", StringComparison.OrdinalIgnoreCase))
{
property.PropertyName = "Short";
}
}
return property;
}
}
Then call for serialization and supply the resolver:
var result = JsonConvert.SerializeObject(myCustomObjectInstance,
new JsonSerializerSettings { ContractResolver = CustomDataContractResolver.Instance });
And the result will be shortened to {"Short":"prop value"} instead of {"LongPropertyName":"prop value"}
More info on custom resolvers here
There is still another way to do it, which is using a particular NamingStrategy, which can be applied to a class or a property by decorating them with [JSonObject] or [JsonProperty].
There are predefined naming strategies like CamelCaseNamingStrategy, but you can implement your own ones.
The implementation of different naming strategies can be found here: https://github.com/JamesNK/Newtonsoft.Json/tree/master/Src/Newtonsoft.Json/Serialization
You can directly use
[JsonProperty(Name = "access_token")]
public string AccessToken { get; set; }
or
[JsonProperty("access_token")]
public string AccessToken { get; set; }
and serialize using Newthonsoft.Json library will be detect how change it

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;
}
}

Categories

Resources