11

I'm trying to figure out how I can specify alternate property names with ASP.NET WebApi - and have it work for deserialization + serialization, and for JSON + XML. I've only uncovered partial solutions so far.

I want to expose the property names as lower case with underscores, and (for example's sake) have different internal names:

External:

  • field-one
  • field-two

Internal:

  • ItemOne
  • ItemTwo

For testing, here's a POST controller action that just relays what it receives:

// POST api/values
public TestSerialization Post([FromBody]TestSerialization value)
{
    return value;
}

And a test entity:

public class TestSerialization
{
    [DataMember(Name = "field_one")] // Doesn't appear to change anything
    public string ItemOne { get; set; }

    [JsonProperty(PropertyName = "field_two")] // Only works for serialization in JSON mode
    public string ItemTwo { get; set; }
}

So far, I've found:

  • [DataMember(Name = "x")] has no effect on serialization in either direction
  • [JsonProperty(Name = "x")] works on serialization (the returning value) when using JSON. (It's a JSON.NET attribute, the default serializer).

For test data, I submit 4 properties, to see which value gets deserialized, and what the property name is on deserialization

  • ItemOne = "Value A"
  • ItemTwo = "Value B"
  • field-one = "Correct 1"
  • field-two = "Correct 2"

How can I achieve this?

08Dc91wk
  • 4,254
  • 8
  • 34
  • 67
Overflew
  • 7,872
  • 10
  • 45
  • 65

2 Answers2

16

Some of your findings/conclusions are incorrect...you can try the following instead:

This should work for both default Xml & Json formatters of web api and for both serialization & deserialization.

[DataContract]
public class TestSerialization
{
    [DataMember(Name = "field_one")]
    public string ItemOne { get; set; }

    [DataMember(Name = "field_two")]
    public string ItemTwo { get; set; }
}

The following should work for Json formatter only and for both serialization & deserialization.

public class TestSerialization
{
    [JsonProperty(PropertyName = "field_one")]
    public string ItemOne { get; set; }

    [JsonProperty(PropertyName = "field_two")]
    public string ItemTwo { get; set; }
}
Kiran
  • 56,921
  • 15
  • 176
  • 161
  • 1
    Ah - With the missed [DataContract] attribute on the class, the serialised result *from* the server is now correct in both JSON & XML. The incoming request from the UI is still only being deserialized with the classes' natural property names, not the DataMember variant. – Overflew Mar 19 '14 at 00:55
  • that should not be happening...can you share your raw request looks like? – Kiran Mar 19 '14 at 01:03
  • 1
    Ah - I was using Postman to create the requests, and was using the 'x-www-form-encoded' tab. Using hand-typed JSON data in the 'raw' tab gives the intended result. Silly me, but I'm a little confused as to why a 'Rest API testing tool' has the fancy key/value editing tools as the first 2 tabs (form-data & form-urlendcoded), where to tools to generate the a JSON request are manual... – Overflew Mar 19 '14 at 01:19
  • JsonProperty doesn't work with the action from the question. It is always ignored. Please describe why you think the OP's findings/conclusions are incorrect. – Florian Winter Feb 07 '17 at 14:42
5

You can force Asp.Net to use the JSON deserializer by passing a JObject to your action, although it is a bit annoying to have to do it like this.

Then you can work with it as a JObject or call .ToObject<T>(); which will then honor the JsonProperty attribute.

// POST api/values
public IHttpActionResult Post(JObject content)
{
    var test = content.ToObject<TestSerialization>();
    // now you have your object with the properties filled correctly.
    return Ok();
}
Ben Wilde
  • 5,552
  • 2
  • 39
  • 36
  • 1
    upvoted this one because when I used this I immediately figured out why my POCO wasn't being deserialized. abstract class fail – Nick Molyneux Jan 12 '17 at 00:24
  • Doesn't work for me. content is always 'null'. It works with ([FromBody]TestSerialization value), but then JsonProperty is ignored. – Florian Winter Feb 07 '17 at 14:46
  • This was and is very helpful for discovering binding errors when using built-in model binding. – Michael K Sep 27 '22 at 01:44