Return JsonResult from web api without its properties

120,346

Solution 1

As someone who has worked with ASP.NET API for about 3 years, I'd recommend returning an HttpResponseMessage instead. Don't use the ActionResult or IEnumerable!

ActionResult is bad because as you've discovered.

Return IEnumerable<> is bad because you may want to extend it later and add some headers, etc.

Using JsonResult is bad because you should allow your service to be extendable and support other response formats as well just in case in the future; if you seriously want to limit it you can do so using Action Attributes, not in the action body.

public HttpResponseMessage GetAllNotificationSettings()
{
    var result = new List<ListItems>();
    // Filling the list with data here...

    // Then I return the list
    return Request.CreateResponse(HttpStatusCode.OK, result);
}

In my tests, I usually use the below helper method to extract my objects from the HttpResponseMessage:

 public class ResponseResultExtractor
    {
        public T Extract<T>(HttpResponseMessage response)
        {
            return response.Content.ReadAsAsync<T>().Result;
        }
    }

var actual = ResponseResultExtractor.Extract<List<ListItems>>(response);

In this way, you've achieved the below:

  • Your Action can also return Error Messages and status codes like 404 not found so in the above way you can easily handle it.
  • Your Action isn't limited to JSON only but supports JSON depending on the client's request preference and the settings in the Formatter.

Look at this: http://www.asp.net/web-api/overview/formats-and-model-binding/content-negotiation

Solution 2

When using WebAPI, you should just return the Object rather than specifically returning Json, as the API will either return JSON or XML depending on the request.

I am not sure why your WebAPI is returning an ActionResult, but I would change the code to something like;

public IEnumerable<ListItems> GetAllNotificationSettings()
{
    var result = new List<ListItems>();
    // Filling the list with data here...

    // Then I return the list
    return result;
}

This will result in JSON if you are calling it from some AJAX code.

P.S WebAPI is supposed to be RESTful, so your Controller should be called ListItemController and your Method should just be called Get. But that is for another day.

Solution 3

I had a similar problem (differences being I wanted to return an object that was already converted to a json string and my controller get returns a IHttpActionResult)

Here is how I solved it. First I declared a utility class

public class RawJsonActionResult : IHttpActionResult
{
    private readonly string _jsonString;

    public RawJsonActionResult(string jsonString)
    {
        _jsonString = jsonString;
    }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var content = new StringContent(_jsonString);
        content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
        var response = new HttpResponseMessage(HttpStatusCode.OK) { Content = content };
        return Task.FromResult(response);
    }
}

This class can then be used in your controller. Here is a simple example

public IHttpActionResult Get()
{
    var jsonString = "{\"id\":1,\"name\":\"a small object\" }";
    return new RawJsonActionResult(jsonString);
}
Share:
120,346

Related videos on Youtube

Vivendi
Author by

Vivendi

Updated on March 03, 2020

Comments

  • Vivendi
    Vivendi about 4 years

    I have a Web API controller and from there I'm returning an object as JSON from an action.

    I'm doing that like this:

    public ActionResult GetAllNotificationSettings()
    {
        var result = new List<ListItems>();
        // Filling the list with data here...
    
        // Then I return the list
        return new JsonResult { Data = result };
    }
    

    But this way the JsonResult object including its Data attribute is serialized as JSON. So my final JSON that is return by the action looks like this:

    {
        "ContentEncoding": null,
        "ContentType": null,
        "Data": {
            "ListItems": [
                {
                    "ListId": 2,
                    "Name": "John Doe"
                },
                {
                    "ListId": 3,
                    "Name": "Jane Doe"
                },
            ]
        },
        "JsonRequestBehavior": 1,
        "MaxJsonLength": null,
        "RecursionLimit": null
    }
    

    I can't serialize this JSON string because the JsonResult object added all kinds of other properties to it. I'm only interested in ListItems, nothing else. But it automatically added things like: ContentType, MaxJsonLength etc...

    Now this won't work for me because of all the other properties in the JSON string...

    var myList = JsonConvert.DeserializeObject<List<ListItems>>(jsonString);
    

    Is there a way to send a JSON object from the action so that it won't add all the properties that I dont need?

    • Daniel A. White
      Daniel A. White over 9 years
      this doesn't look like web api but regular mvc.
    • Vivendi
      Vivendi over 9 years
      @DanielA.White Well, it is Web API. My controller also extends from it.
    • Daniel A. White
      Daniel A. White over 9 years
      you shouldn't be using ActionResult/JsonResult.
    • Vivendi
      Vivendi over 9 years
      Ah I see, that could explain the problem then :p
    • DaniCE
      DaniCE over 9 years
      To return json data in a "regular controller", your method has to return new Json, see: stackoverflow.com/a/227638/19046
  • demoncodemonkey
    demoncodemonkey over 9 years
    +1 however about your last point, REST has nothing to do with the name of the controller or method.
  • Tim B James
    Tim B James over 9 years
    @demoncodemonkey not really, but from the naming convention going on in the Question, I can guess that they have loads of Get's within the same controller that return different objects. Cleaner (IMO) to keep HttpGet's named Get
  • demoncodemonkey
    demoncodemonkey over 9 years
    Agree but nothing to do with REST :)
  • mentat
    mentat over 8 years
    nice answer but I suppose with webapi2, we should be using IHttpActionResult now: stackoverflow.com/questions/21758615/…