user3520332
user3520332

Reputation: 251

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

I am retrieving JSON from an API. I am using newtonsoft (this is json.net right?) to deserialize this into a list of objects. It works.

Unfortunately I also need to pass this along to someone else as JSON (they can't call the API directly only I have access to it). I say unfortunately because I need to OUTPUT my JSON that is different from what is being received (the property names need to be different).

For example, I have a class called Person, with a property called Name. I want to get "People", so I make my request to that API to get JSON as above, and get back a list of Person. Unfortunately the API doesn't return me people with Name properties, it returns me pname. So to map this, I just do:

 [JsonProperty("pname")]

This is all well and good - it converts pname to name and my class now has the value! I have a list of people with names.

Now I need to give this list of objects BACK to someone else as "Name", However when I serialize my people class back to JSON, it writes out the JSON as "pname" when I really want to write it out as "Name". I suspect it's picking up the "JsonProperty".

Is there a way to just have it use pname for deserialization, but use the original property value for serialization?

Thanks!

Upvotes: 14

Views: 10018

Answers (4)

Romain Donck
Romain Donck

Reputation: 21

Maybe I'm late to the party, but this also works:

[JsonPropertyName("pname")]
public string? PName { private get; set; }

public string? Name => PName;

Upvotes: 2

user5683877
user5683877

Reputation:

The simple solution is to create two properties.

Upvotes: 0

evanmcdonnal
evanmcdonnal

Reputation: 48154

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

Upvotes: 7

Tim S.
Tim S.

Reputation: 56586

You might be able to write a custom JsonConverter to do it with just one Person class, but I'd recommend having separate classes, since the data is modeled differently in the two places. Even if you don't plan to right now, you might find yourself needing to deserialize from Name or serialize to pname at some point. This also allows your classes to differ more substantially. You could use AutoMapper (or similar) to easily convert between the two. E.g.

public class PersonFromThatApi
{
    [JsonProperty("pname")]
    public string Name { get; set; }
}
public class Person
{
    public string Name { get; set; }
}

Mapper.CreateMap<PersonFromThatApi, Person>();
Mapper.CreateMap<Person, PersonFromThatApi>();

var person1 = JsonConvert.DeserializeObject<PersonFromThatApi>(
                               @"{""pname"":""George""}");
Person person2 = Mapper.Map<Person>(person1);
string s = JsonConvert.SerializeObject(person2); // {"Name":"George"}

And yes, Newtonsoft.Json is the namespace of Json.NET. Don't ask me why they chose totally different names for those two things.

Upvotes: 0

Related Questions