Search code examples
c#asp.net-web-api2putasp.net-web-api-routing

PUT in Web API will always put "0" to server


I'm starting with Web API (I've been away from web dev for awhile and it seems nobody cares about SOAP anymore), but I ran into some trouble while trying to PUT.

I followed an online tutorial and it works fine for GET and DELETE. In order to test, I'm using Postman, as this will be called from another service which is also tested with Postman. Here's the code for GET:

Get all books:

// GET: api/Books
public IEnumerable<Book> Get()
{
    return Library.Books;
}

Get book by ID:

// GET: api/Books/<int>
public IHttpActionResult Get(int id)
{
    Book book = Library.Books.FirstOrDefault(l => l.ID == id);

    if (book != null)
        return ResponseMessage(Request.CreateResponse<Book>(HttpStatusCode.OK, book));
    else
        return ResponseMessage(Request.CreateResponse<string>(HttpStatusCode.NotFound, "Book not found."));
}

Delete book by ID:

// DELETE: api/Books/<int>
public IHttpActionResult Delete(int id)
{
    Book book = Library.Books.FirstOrDefault(l => l.ID == id);

    if (book != null)
    {
        Library.Books.Remove(book);
        return ResponseMessage(Request.CreateResponse(HttpStatusCode.OK));
    }
    else
        return ResponseMessage(Request.CreateResponse<string>(HttpStatusCode.NotFound, "Book not found."));
}

All of them run fine and will serve my purposes, as I do have to return a list of objects, so it's all fine.

BTW, http://localhost/api/Books/1 works pretty well when GET or DELETE is selected (I don't really need to get into postman's inner workings right now)

But I've altered the PUT method as I only need to send some int (an address) to this service. Here's the test code:

// PUT: api/Books/<int>
public IHttpActionResult Put([FromBody]int address)
{
    if (address == 0)
        return ResponseMessage(Request.CreateResponse<string>(HttpStatusCode.BadRequest, "Value cannot be zero"));
    else
        return ResponseMessage(Request.CreateResponse(HttpStatusCode.OK));
}

While debugging, the parameter "address" will always be zero if called as such: http://localhost/api/Books/80, or any other int. In other words, my response to PUT will always be "Value cannot be zero". I've tried removing [FromBody] and adding the [HttpPut] attribute to the PUT method, but it only makes things worse. I know that's pretty newbish, but like I said, I haven't dealt with web dev in ages. Please advice.


Solution

  • The code you have:

    public IHttpActionResult Put([FromBody]int address)
    {
    }
    

    Expects you to send a request body containing the number.

    In a REST API, the PUT verb is typically implemented in a way like this:

    public IHttpActionResult Put(int id, [FromBody]Book book)
    {
        //Update book with id == id with info from book
    }
    

    Then you can send an HTTP request to http://myapi.com/api/Books/23 with a request body like:

    {
        "title": "Updated title",
        "author": "Updated author"
    }
    

    Edit:

    Actually all this is just the typical pattern. If you wish, you can do attribute-based routing and achieve what you want with:

    [RoutePrefix("api/Books")]
    public class BooksController : ApiController
    {
        [HttpPut]
        [Route("{address}")]
        public IHttpActionResult Put(int address)
        {
    
        }
    }
    

    In this case you use attribute-based routing to define what the route is for the actions. [RoutePrefix] here defines what all the routes in the controller should start with.