Use Different Name for Serializing and Deserializing with JSON.Net

Use different name for serializing and deserializing with Json.Net

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!'}"

Json.NET deserialize or serialize json string and map properties to different property names defined at runtime

You could use a custom ContractResolver to do this. Basically it is the same idea as putting a [JsonProperty] attribute on each class member for which you want to map to a different JSON property name, except you do it programmatically via the resolver. You can pass a dictionary of your desired mappings to the resolver when setting it up just before deserializing.

Here is what the custom resolver code might look like:

class DynamicMappingResolver : DefaultContractResolver
{
private Dictionary<Type, Dictionary<string, string>> memberNameToJsonNameMap;

public DynamicMappingResolver(Dictionary<Type, Dictionary<string, string>> memberNameToJsonNameMap)
{
this.memberNameToJsonNameMap = memberNameToJsonNameMap;
}

protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty prop = base.CreateProperty(member, memberSerialization);
Dictionary<string, string> dict;
string jsonName;
if (memberNameToJsonNameMap.TryGetValue(member.DeclaringType, out dict) &&
dict.TryGetValue(member.Name, out jsonName))
{
prop.PropertyName = jsonName;
}
return prop;
}
}

To use the resolver, first construct a Dictionary<Type, Dictionary<string, string>> containing your mappings. The outer dictionary's key is the the class type(s) whose properties you want to map; the inner dictionary is a mapping of the class property names to JSON property names. You only need to provide a mapping for the properties whose names don't already match the JSON.

So, for example, if your JSON looked like this (notice the changed names of the properties inside the details object)...

{
"values": {
"details": {
"foo": "94",
"bar": "47",
"baz": "32",
"quux": 1
},
count: 4
}
}

...and you wanted to map it to the classes in your question, you would create the dictionary like this:

var map = new Dictionary<Type, Dictionary<string, string>>
{
{
typeof(Details),
new Dictionary<string, string>
{
{"property1", "foo"},
{"property2", "bar"},
{"property3", "baz"},
{"property4", "quux"}
}
}
};

The last step is to set up the serializer settings with a new resolver instance, giving it the mapping dictionary you just constructed, and then pass the settings to JsonConvert.DeserializeObject().

var settings = new JsonSerializerSettings
{
ContractResolver = new DynamicMappingResolver(map)
};

var root = JsonConvert.DeserializeObject<RootObject>(json, settings);

Here is a demo: https://dotnetfiddle.net/ULkB0J

C# - Set different PropertyName between JSON serialization and deserialization

I solved it through WriteJson method as Chetan Ranpariya suggested:

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
JArray result = new JArray();

if (value.GetType().IsGenericType && value is IEnumerable)
{
IEnumerable list = value as IEnumerable;

foreach(var obj in list)
{
result.Add(GetObjectJson(obj));
}
}

result.WriteTo(writer);
}

private JObject GetObjectJson(object obj)
{
JObject jObj = new JObject();
PropertyInfo[] props = obj.GetType().GetProperties();

foreach (PropertyInfo prop in props)
{
if (!prop.PropertyType.ToString().Contains("System"))
jObj.Add(char.ToLowerInvariant(prop.Name[0]) + prop.Name.Substring(1), GetObjectJson(prop.GetValue(obj)));
else
jObj.Add(char.ToLowerInvariant(prop.Name[0]) + prop.Name.Substring(1), JToken.FromObject(prop.GetValue(obj)));
}

return jObj;
}

As in object value parameter I receive the object (which is a list, in this case) I cast it and iterate over it's objects.

Since every object can have primitive and non primitive properties, I created a separated function to use it recursively in case I found a nested object.

How can I change property names when serializing with Json.net?

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

.NET NewtonSoft JSON deserialize map to a different property name

Json.NET - Newtonsoft has a JsonPropertyAttribute which allows you to specify the name of a JSON property, so your code should be:

public class TeamScore
{
[JsonProperty("eighty_min_score")]
public string EightyMinScore { get; set; }
[JsonProperty("home_or_away")]
public string HomeOrAway { get; set; }
[JsonProperty("score ")]
public string Score { get; set; }
[JsonProperty("team_id")]
public string TeamId { get; set; }
}

public class Team
{
public string v1 { get; set; }
[JsonProperty("attributes")]
public TeamScore TeamScores { get; set; }
}

public class RootObject
{
public List<Team> Team { get; set; }
}

Documentation: Serialization Attributes

JsonProperty - Use different name for deserialization, but use original name for serialization?

You can create a custom contract resolver that sets the property names back to the ones you've defined in the C# class before serilization. Below is some example code;

class OriginalNameContractResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
// Let the base class create all the JsonProperties
IList<JsonProperty> list = base.CreateProperties(type, memberSerialization);

// assign the C# property name
foreach (JsonProperty prop in list)
{
prop.PropertyName = prop.UnderlyingName;
}

return list;
}
}

Use it like this;

    JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Formatting = Formatting.Indented;
if (useLongNames)
{
settings.ContractResolver = new OriginalNameContractResolver();
}

string response = JsonConvert.SerializeObject(obj, settings);

Json.Net deserialize and serialize properties with names that change

There are a couple of approaches you could take to handle this. The first (and simplest) approach is to use nested dictionaries in your TransactionChangeLog class:

public class TransactionChangeLog
{
[JsonProperty(PropertyName = "transaction_id")]
public int TransactionId { get; set; }

[JsonProperty(PropertyName = "status")]
public TransactionStatus Status { get; set; }

[JsonProperty(PropertyName = "changelog")]
public Dictionary<DateTime, Dictionary<string, TransactionChange>> Changelog { get; set; }
}

public class TransactionChange
{
public string From { get; set; }
public string To { get; set; }
}

You can then deserialize and dump out the data like this:

TransactionChangeLog changeLog = JsonConvert.DeserializeObject<TransactionChangeLog>(json);

Console.WriteLine("TransactionId: " + changeLog.TransactionId);
Console.WriteLine("TransactionStatus: " + changeLog.Status);
foreach (var dateKvp in changeLog.Changelog)
{
Console.WriteLine(dateKvp.Key); // change date
foreach (var fieldKvp in dateKvp.Value)
{
Console.WriteLine(" changed " + fieldKvp.Key + " from '" + fieldKvp.Value.From + "' to '" + fieldKvp.Value.To + "'");
}
}

Fiddle: https://dotnetfiddle.net/vXNcKi


Although the above will work, it's a little bit awkward to work with the nested dictionaries. Another approach is to use a JsonConverter to handle the deserialization of the varying JSON. This will allow you to use the classes as you defined them in your question. Here is how you might write the converter:

public class ChangeLogConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(ICollection<TransactionChange>);
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
List<TransactionChange> changes = new List<TransactionChange>();
JObject changelog = JObject.Load(reader);
foreach (JProperty dateProp in changelog.Children<JProperty>())
{
DateTime changeDate = DateTime.ParseExact(dateProp.Name, "yyyy-MMM-dd hh:mm tt", CultureInfo.InvariantCulture);
foreach (JProperty fieldProp in dateProp.Value.Children<JProperty>())
{
TransactionChange change = new TransactionChange();
change.ChangeDate = changeDate;
change.Field = fieldProp.Name;
change.From = (string)fieldProp.Value["from"];
change.To = (string)fieldProp.Value["to"];
changes.Add(change);
}
}
return changes;
}

public override bool CanWrite
{
get { return false; }
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}

To use the converter, add a [JsonConverter] attribute to the Changelog property in your TransactionChangeLog class:

public class TransactionChangeLog
{
[JsonProperty(PropertyName = "transaction_id")]
public int TransactionId { get; set; }

[JsonProperty(PropertyName = "status")]
public TransactionStatus Status { get; set; }

[JsonProperty(PropertyName = "changelog")]
[JsonConverter(typeof(ChangeLogConverter))]
public ICollection<TransactionChange> Changelog { get; set; }
}

You can then deserialize and dump out the data as you normally would:

TransactionChangeLog changeLog = JsonConvert.DeserializeObject<TransactionChangeLog>(json);
Console.WriteLine("TransactionId: " + changeLog.TransactionId);
Console.WriteLine("TransactionStatus: " + changeLog.Status);
foreach (TransactionChange change in changeLog.Changelog)
{
Console.WriteLine(change.ChangeDate + " - changed " + change.Field + " from '" + change.From + "' to '" + change.To + "'");
}

Fiddle: https://dotnetfiddle.net/1d3pUa



Related Topics



Leave a reply



Submit