Web Api - How to return a dynamic object with 201 status code

Xavier Egea picture Xavier Egea · Jun 25, 2014 · Viewed 7.8k times · Source

I'm trying to return the recently added entity Id in a Web Api action method as a JSON. Example:

{ bookId = 666 }

The Controller Action code is as follows:

[HttpPost, Route("")]
public HttpResponseMessage Add(dynamic inputs)
{
    int bookId = bookService.Add(userId, title);

    dynamic book = new ExpandoObject();
    book.bookId = bookId

    return new HttpResponseMessage(HttpStatusCode.Created)
    {
        Content = new ObjectContent<dynamic>(book,
            new JsonMediaTypeFormatter
            {
                UseDataContractJsonSerializer = true
            })
    };
}

The problem here is to accomplish it returning a dynamic content (without Dto) and returning the HttpStatusCode.Created (201 http status).

Now I have the next error:

{"Message":"An error has occurred.","ExceptionMessage":"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.","ExceptionType":"System.InvalidOperationException","StackTrace":null,"InnerException":{"Message":"An error has occurred.","ExceptionMessage":"No se espera el tipo 'System.Dynamic.ExpandoObject' ...

if I change the new ObjectContent<dynamic> by new ObjectContent<ExpandoObject> I get the correct 201 status header response, but the JSON result is as as follows:

[{"Key":"bookId","Value":666}]

So, is it possible to return { bookId: 666} using dynamics (not Dtos) setting the header status code to 201 (Created)?

Thank you for your help.

Answer

James picture James · Jun 25, 2014

The behaviour you see is correct because a dynamic / ExpandoObject is effectively just a wrapper around a Dictionary<TKey, TValue>.

If you want it to be serialized as an object then you should use an anonymous object instead of an ExpandoObject e.g.

int bookId = bookService.Add(userId, title);

var book = new { bookId = bookId };

return new HttpResponseMessage(HttpStatusCode.Created)
{
    Content = new ObjectContent<object>(book,
        new JsonMediaTypeFormatter
        {
            UseDataContractJsonSerializer = true
        })
};

If JsonMediaTypeFormatter doesn't support anonymous objects then you could try using the default serializer

return this.Request.CreateResponse(HttpStatusCode.OK, book);