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?

2 Answers 2

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; }
}
Sign up to request clarification or add additional context in comments.

4 Comments

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.
that should not be happening...can you share your raw request looks like?
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...
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.
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();
}

3 Comments

upvoted this one because when I used this I immediately figured out why my POCO wasn't being deserialized. abstract class fail
Doesn't work for me. content is always 'null'. It works with ([FromBody]TestSerialization value), but then JsonProperty is ignored.
This was and is very helpful for discovering binding errors when using built-in model binding.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.