Search code examples
c#.netjsonhttpnancy

JSON body is not deseralized by NancyModule


I have a route in my module that is supposed to accept a JSON body representing blog post. Problem is that the request body is not seralized. If I debug I see the following values on the request:

this.Request.Body.Length: 93
x.Keys.Count: 0

The route

Post["/Blog"] = x =>
        {
            var post = this.Bind<Post>(); //Breakpoint

            PostService.Save(post);
            return post;
        };

The HTTP-request

POST /Blog HTTP/1.1
Host: localhost:57888
Content-Type: application/json
Cache-Control: no-cache

{ "Post": { "Title":"Hello", "Content":"World", "Created":"2014-04-26" } }

Solution

  • Deserialization:

    There's nothing wrong with your code, the problem is you've wrapped your JSON:

    Your object has a property called Post, then it has the actual post.

    Update your body to look like:

    { "Title":"Hello", "Content":"World", "Created":"2014-04-26" }

    This most likely matches the properties on your Post object.


    Below is serialization to the client, not what the question was asking for


    Serialization:

    You need to add an Accept header.

    I've written about Nancy Conneg here:

    http://www.philliphaydon.com/2013/04/22/nancyfx-revisiting-content-negotiation-and-apis-part-1/

    Your scenario doesn't work because you're only telling the server what your content is, not what you expect in return.

    Accept

    Using the Chrome Plugin - Postman, you can test your scenario similar to this:

    enter image description here

    By applying the Accept header as application/json the content returned will be serialized.

    .json url

    Alternatively, you can can add .json to the end your URL to return it as JSON:

    http://yoursite.com/blog.json

    This will force the JSON serializer to kick in.

    .AsJson()

    If you want to always return JSON regardless, you can return your result using .AsJson()

    Post["/Blog"] = x =>
    {
        var post = this.Bind<Post>(); //Breakpoint
    
        PostService.Save(post);
        
        return Response.AsJson(post);
    };
    

    Note, if you're returning a dynamic type then you will need to cast it: return Response.AsJson((object)post);