10

I am receiving JSON data from a web API that looks like this:

[ { "id": 1 "error_message": "An error has occurred!" } ] 

I deserialize this data to objects of the following type:

public class ErrorDetails { public int Id { get; set; } [JsonProperty("error_message")] public string ErrorMessage { get; set; } } 

Later in my application I would like to serialize the ErrorDetails object again to JSON but using the property name ErrorMessage instead of error_message. So the result would look like this:

[ { "Id": 1 "ErrorMessage": "An error has occurred!" } ] 

Is there an easy way I can accomplish this with Json.Net? Perhaps using a custom resolver and some attributes like:

public class ErrorDetails { public int Id { get; set; } [SerializeAs("ErrorMessage")] [DeserializeAs("error_message")] public string ErrorMessage { get; set; } } 

But the resolver doesn't tell me when I'm serializing or deserializing.

4
  • You need two classes. Each class is a contract for the json to generate or read Commented Jun 19, 2017 at 14:17
  • You could use SnakeCaseNamingStrategy while deserializing that JSON. See here for an example of how to do it. Commented Jun 20, 2017 at 8:58
  • That seems very interesting. Add this as an answer please. Commented Jun 20, 2017 at 12:39
  • Related post - How can I change property names when serializing with Json.net? Commented Sep 6, 2019 at 5:56

3 Answers 3

18

You can make use of the JsonSerializerSettings, the ContractResolver and the NamingStrategy.

public class ErrorDetails { public int Id { get; set; } public string ErrorMessage { get; set; } } var json = "{'Id': 1,'error_message': 'An error has occurred!'}"; 

For dezerialization you could use the SnakeCaseNamingStrategy.

var dezerializerSettings = new JsonSerializerSettings { ContractResolver = new DefaultContractResolver { NamingStrategy = new SnakeCaseNamingStrategy() } }; var obj = JsonConvert.DeserializeObject<ErrorDetails>(json, dezerializerSettings); 

To serialize the object again you dont have to change the JsonSerializerSettings as the default will use the property name.

var jsonNew = JsonConvert.SerializeObject(obj); 

jsonNew = "{'Id': 1,'ErrorMessage': 'An error has occurred!'}"


Or you could create a contract resolver which can decide which name to use. Then you can decide when you dezerialize and serialize if you want to use the pascal case name format or the one with the underscore.

public class CustomContractResolver : DefaultContractResolver { public bool UseJsonPropertyName { get; } public CustomContractResolver(bool useJsonPropertyName) { UseJsonPropertyName = useJsonPropertyName; } protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { var property = base.CreateProperty(member, memberSerialization); if (!UseJsonPropertyName) property.PropertyName = property.UnderlyingName; return property; } } public class ErrorDetails { public int Id { get; set; } [JsonProperty("error_message")] public string ErrorMessage { get; set; } } var json = "{'Id': 1,'error_message': 'An error has occurred!'}"; var serializerSettings = new JsonSerializerSettings() { ContractResolver = new CustomContractResolver(false) }; var dezerializerSettings = new JsonSerializerSettings { ContractResolver = new CustomContractResolver(true) }; var obj = JsonConvert.DeserializeObject<ErrorDetails>(json, dezerializerSettings); var jsonNew = JsonConvert.SerializeObject(obj, serializerSettings); 

jsonNew = "{'Id': 1,'ErrorMessage': 'An error has occurred!'}"

Sign up to request clarification or add additional context in comments.

1 Comment

One thing to point out here is that if you decide to use CamelCasePropertyNamesContractResolver as the base instead of DefaultContractResolver then the resulting property names won't be camel cased. Therefore you'd have to manually camel case the name e.g. property.UnderlyingName.ToCamleCase(). We can't use the JSON.Net ToCamelCase() method directly because it's within an internal StringUtils class so you'd have to provide your own: github.com/JamesNK/Newtonsoft.Json/blob/…
3

I liked the answer by @lee_mcmullen, and implemented it in my own code. Now I think I've found a slightly neater version.

public class ErrorDetails { public int Id { get; set; } // This will deserialise the `error_message` property from the incoming json and store it in the new `GetErrorMessage` property [JsonProperty("error_message")] public string GetErrorMessage { get { return ErrorMessage; } set { ErrorMessage = value; } } // If this method returns false then the property after the `ShouldSerialize` prefix will not be serialised into the output public bool ShouldSerializeGetErrorMessage() => false; // The serialised output will return `ErrorMessage` with the value set from `GetErrorMessage` i.e. `error_message` in the original json public string ErrorMessage { get; set; } } 

The reason I like this better is that in more complicated models it allows for inheritance while keeping all of the "old" custom stuff separate

public class ErrorDetails { public int Id { get; set; } public string ErrorMessage { get; set; } } // This is our old ErrorDetails that hopefully we can delete one day public class OldErrorDetails : ErrorDetails { // This will deserialise the `error_message` property from the incoming json and store it in the new `GetErrorMessage` property [JsonProperty("error_message")] public string GetErrorMessage { get { return ErrorMessage; } set { ErrorMessage = value; } } // If this method returns false then the property after the `ShouldSerialize` prefix will not be serialised into the output public bool ShouldSerializeGetErrorMessage() => false; } 

1 Comment

This very nice answer and while it has some overhead in code it does produce good JSON result. Nice!
2

Another way of achieving a different property name when serialising vs deserisalising is by using the ShouldSerialize method: https://www.newtonsoft.com/json/help/html/ConditionalProperties.htm#ShouldSerialize

The docs say:

To conditionally serialize a property, add a method that returns boolean with the same name as the property and then prefix the method name with ShouldSerialize. The result of the method determines whether the property is serialized. If the method returns true then the property will be serialized, if it returns false then the property will be skipped.

E.g:

public class ErrorDetails { public int Id { get; set; } // This will deserialise the `error_message` property from the incoming json into the `GetErrorMessage` property [JsonProperty("error_message")] public string GetErrorMessage { get; set; } // If this method returns false then the property after the `ShouldSerialize` prefix will not be serialised into the output public bool ShouldSerializeGetErrorMessage() => false; // The serialised output will return `ErrorMessage` with the value from `GetErrorMessage` i.e. `error_message` in the original json public string ErrorMessage { get { return GetErrorMessage; } } } 

This results in slightly more overhead so be careful if dealing with lots of properties or with lots of data but for small payloads, and if you don't mind messing up your DTO class a little, then this could be a quicker solution than writing custom contract resolvers etc.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.