1

I need to get my JSON output looking like this:

{
    "User": {
        "Id" : "1",
        "FirstName" : "John",
        "LastName" : "Doe",
        ... etc

My first issue is that the class name being serialized here is called Person not User, and I am not able to change that. But the JSON needs User.

Secondly, my Web API method is not returning a root node here at all, what exactly am I doing wrong?

My JSON looks like this:

{"Id":1,"BossId":null,"Title":"CEO","GivenName":"Doe", ... etc

This is so badly formatted that even my Chrome extension to make JSON pretty doesn't recognize this stuff.

Here's my Web API controller to get a user by ID, which is resulting in the above:

[Route("{id:int}")]
public HttpResponseMessage GetPerson(int id) {

    Person person = repository.Get(id);

    if (person == null) {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }

    return Request.CreateResponse(HttpStatusCode.OK, person);

}

I am also going to have to map class properties to different names here, which is a separate issue.

For example, the class has GivenName and FamilyName but the JSON needs FirstName and LastName. Is there an attribute I can apply to the property for this?

Any help would be appreciated.

Patrick
  • 5,526
  • 14
  • 64
  • 101
  • I'd suggest to post your class along with sample json you want to produce. – Saleem Mar 22 '16 at 00:11
  • 3
    `This is so badly formatted that even my Chrome extension to make JSON pretty doesn't recognize this stuff.` - That looks like perfectly fine JSON to me. Anyway, you'll need to wrap an anonymous object if you want a root-object, like so: `return Request.CreateResponse(HttpStatusCode.OK, new { User = person });` – Rob Mar 22 '16 at 00:11
  • The class is a simple small POCO class resembling a Person ... first name, last name, ID ... it does have one IEnumerable for multiple addresses but that is all returning OK in the JSON, it's just naming issues and the root node problem. – Patrick Mar 22 '16 at 00:25
  • I don't know why the Chrome JSON formatting extension isn't doing it's job on this. I have tested it against multiple other JSON endpoints and it does indeed format nicely. It refuses to do anything with what I am getting from the controller here. I can halt the debugger and in the JSON viewer it looks ok (tree'd out, nested properly) so it must be valid. – Patrick Mar 22 '16 at 00:27

2 Answers2

3

ASP.NET WebApi uses JSON.NET for serialization to json. So you can change name in this way:

class Person
{
    [JsonProperty(PropertyName = "LastName")]
    public string FamilyName { get; set; }
    ...
}

EDIT

For add root element look at this answer. I didn't try this but looks nice.

Community
  • 1
  • 1
BWA
  • 5,672
  • 7
  • 34
  • 45
  • Thanks ... I hadn't realize they actually brought JSON.NET into the mix until doing some searches on this. It does make it a lot easier and this was what I needed for the property names. – Patrick Mar 22 '16 at 00:43
  • Should I be expecting "Content-Type: text/html; charset=utf-8" in Fiddler instead of "application/json" here? If not how do I go about changing that? – Patrick Mar 22 '16 at 01:54
  • Disregard, I found out what was breaking this entire thing. I added a line from another SO post regarding JSON formatting and that was messing it up ("config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));") ... I removed this line from WebApiConfig.cs and now the browser is showing this as properly formatted JSON and the content-type is correct. – Patrick Mar 22 '16 at 01:56
  • I've accepted this answer as it partially solved this ... the attribute to rename the properties when serialized. However, @Rob posted an excellent comment above regarding the root node name issue. Very simple and elegant, and a minor change to what I had: `return Request.CreateResponse(HttpStatusCode.OK, new { User = person });` – Patrick Mar 22 '16 at 07:33
1

Assuming you are using the Newtonsoft Json.Net, the most popular .Net Json serializer, following modifications are required:

  1. Wrap the Person object inside a wrapper and assign a JsonProperty to it:

     [JsonObject]
     public class Wrapper
     {
       [JsonProperty("User")]
       public Person Person {get; set;}
     }
    
  2. Now use the same JsonProperty inside the Person class too:

     [JsonObject]
     public class Person
     {
       [JsonProperty("FirstName")]
       public string GivenName {get; set;}
    
       [JsonProperty("LastName")]
       public string FamilyName {get; set;}
    
       ... More Properties
     }
    

Now while filling the response.following need to be done:

Wrapper w = new Wrapper();
w.Person = <assign Value>
return Request.CreateResponse(HttpStatusCode.OK, w);

One last thing Json unlike XML doesn't have a concept of a root node, it's nameless, that's why wrapper doesn't come anywhere and it would start from first object marked as User in this case, Json is a like an anonymous type in C#, internally a Key Value pair, since Keys are always string

Mrinal Kamboj
  • 11,300
  • 5
  • 40
  • 74
  • This answer from Rob in a comment actually is cleaner and does product the expected result with regards to the root node: Request.CreateResponse(HttpStatusCode.OK, new { User = person }); – Patrick Mar 22 '16 at 00:57
  • In an enterprise system, where Rest services are accessed using a Web API, directly modifying the HttpResponseMessage is not a good practice, you need to allow Web API do it for you. Exception case would be where you add filters to handle error and create a friendly HttpResponseMessage. Irrespective of answer you choose, please try using Web API inbuilt entity serialization, which needs a wrapper class as suggested – Mrinal Kamboj Mar 22 '16 at 07:39
  • I appreciate your comments and have been reading more about the process. It just seems sort of "ugly" (if you will) to have to create an additional "Wrapper" class just to get some text in the JSON root node. `new { User = person }` accomplishes it and seems much more elegant to me. But if this is not a best practice, I will continue to look into it. This particular application is not enterprise and I don't have to worry about this. Sometimes "best practices", while great, make things overly complicated when you don't need it. – Patrick Mar 22 '16 at 07:45
  • Certainly your prerogative, you may find different opinions :) – Mrinal Kamboj Mar 22 '16 at 07:47
  • I always do. I think that's why I keep coming back here! – Patrick Mar 22 '16 at 07:48