11

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!

user3520332
  • 221
  • 4
  • 10
  • 2
    possible duplicate of [How to ignore JsonProperty(PropertyName = “someName”) when serializing json?](http://stackoverflow.com/q/20622492/10263) – Brian Rogers Apr 10 '14 at 18:36

4 Answers4

7

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);
evanmcdonnal
  • 46,131
  • 16
  • 104
  • 115
  • Thank you for the edit. For some reason the "code" and other formatting buttons are all just white in my browser :( – evanmcdonnal Apr 10 '14 at 16:38
  • You're welcome! Sounds like an image didn't load right, I'd try refreshing the page and/or clearing your cache. – Tim S. Apr 10 '14 at 16:52
  • Thank you so much, this worked! NOW, any thoughts on how to get it conditionally? If I want to keep one field, but keep the original name of another? – user3520332 Apr 10 '14 at 20:24
  • @user3520332 yeah here a couple ideas; 1) add logic within the foreach loop so you don't do `prop.PropertyName = prop.UnderlyingName;` for the ones which you don't want to change or 2) don't iterate over them in the first place. The code calls `base.CreateProperties` there is also a `CreateProperty` method you could use to retrieve only the property you want to modify. Of course, that makes your code far less general but if that's what you need so be it. – evanmcdonnal Apr 10 '14 at 20:33
  • that's what I was thinking as well, ok thanks. Could there be a way to somehow "decorate" some fields to be ignored by the contract resolver? – user3520332 Apr 10 '14 at 20:34
  • @user3520332 probably, I'd have to do a little research though. I know you have access to those various decorations/annotations through json.NET. I'd recommend posting another question. If I have time I'll try to answer it, if not someone else probably will. You're looking for too advanced of features :p – evanmcdonnal Apr 10 '14 at 20:52
  • Sorry one last question, when I add a watch to the string after serialization it looks as valid JSON, but when I hit the controller directly in IE it returns a .json file which comes back with \" (escaping the quotes) and the first char is " and the last char is ". if I remove the ""'s from the beginning/end, and remove all \'s (escaping the quotes) it says it's valid JSON, but otherwise it says it's not valid JSON. Any ideas why it would do that? Is there a formatting setting I need? Why would the .json file being returned look like that? – user3520332 Apr 10 '14 at 21:15
  • @user3520332 I'm not sure but I suspect it has nothing to do with the serialization. If you just do a normal serialization and check the value in the controller is it also weird like that? – evanmcdonnal Apr 10 '14 at 21:46
  • 1
    Searched all over the internet. Only this helped. Thanks a lot. – Ashoor Feb 06 '20 at 10:58
1

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

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

public string? Name => PName;
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
0

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.

Tim S.
  • 55,448
  • 7
  • 96
  • 122
0

The simple solution is to create two properties.