Search code examples
asp.net-web-apiasp.net-web-api2asp.net-web-api-routing

WebApi routing - many POST methods


I have WebAPI 2 application. How can I specify 2 or more POST methods?

I have the following WebApiConfig:

public static void Register(HttpConfiguration config)
{
    config.SuppressDefaultHostAuthentication();
    config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

    // Web API routes
    config.MapHttpAttributeRoutes();

    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
}

and API Controller:

[RoutePrefix("api/books")]
public class BooksController : ApiController
{
    [Route("Post1")]
    [HttpPost]
    public IQueryable<string> Post1(string str)
    {
        return null;
    }

    [Route("Post2")]
    [HttpPost]
    public IQueryable<string> Post2(int id)
    {
        return null;
    }
}

It works neither I call:

/api/books/post1

nor

/api/books/post2

why and how to solve it?

UPDATE:

Problem is solved, problem was in simple types as parameters. I get 404 error

Message=No HTTP resource was found that matches the request URI 'http://localhost:37406/api/books/post1'.

with request:

POST http://localhost:37406/api/books/post1 HTTP/1.1
User-Agent: Fiddler
Host: localhost:35979
Content-Type: application/json; charset=utf-8

{
    "str" : "Fffff"
}

and code:

    [Route("Post1")]
    [HttpPost]
    public HttpResponseMessage Post1(string str)
    {
        return Request.CreateResponse();
    }


    [Route("Post2")]
    [HttpPost]
    public HttpResponseMessage Post2(int id)
    {
        return Request.CreateResponse();
    }

but it works fine with complex type:

   [HttpPost]
   [Route("Post1")]
    public HttpResponseMessage Post1(Book book)
    {
        return Request.CreateResponse();
    }

    [HttpPost]
    [Route("Post2")]
    public HttpResponseMessage Post2(Book book)
    {
        return Request.CreateResponse();
    }



public class Book
{
    public int BookId { get; set; }
    public string Title { get; set; }
    public string Author { get; set; }
    public string Genre { get; set; }
}

Thank you Nkosi

UPDATE 2:

but it works when parameter is marked with [FromBody]

    [Route("Post1")]
    [HttpPost]
    public HttpResponseMessage Post1([FromBody]string str)
    {
        return Request.CreateResponse();
    }


    [Route("Post2")]
    [HttpPost]
    public HttpResponseMessage Post2([FromBody]int id)
    {
        return Request.CreateResponse();
    }

(for complex types it's unnecessary). Logically, but Route error confused :)


Solution

  • Excerpt taken from Attribute Routing in ASP.NET Web API 2

    HTTP Methods

    Web API also selects actions based on the HTTP method of the request (GET, POST, etc). By default, Web API looks for a case-insensitive match with the start of the controller method name. For example, a controller method named PutCustomers matches an HTTP PUT request.

    You can override this convention by decorating the mathod with any the following attributes:

    [HttpDelete]
    [HttpGet]
    [HttpHead]
    [HttpOptions]
    [HttpPatch]
    [HttpPost]
    [HttpPut]
    

    The following example maps the CreateBook method to HTTP POST requests.

    [Route("api/books")]
    [HttpPost]
    public HttpResponseMessage CreateBook(Book book) { ... }
    

    Example:

    public class Book {
        public int BookId{get;set;}
        public string Title{get;set;}
        public string Author{get;set;}
        public string Genre{get;set;}
    }
    
    [RoutePrefix("api/books")]
    public class BooksController : ApiController
    {
        // GET api/books
        [Route("")]
        public IEnumerable<Book> Get() { ... }
    
        // GET api/books/5
        [Route("{id:int}")]
        public Book Get(int id) { ... }
    
        // POST api/books
        [HttpPost]
        [Route("")]
        public HttpResponseMessage Post1(Book book) { ... }
    
        // POST api/books/alternate
        [HttpPost]
        [Route("alternate")]
        public HttpResponseMessage Post2(Book book) { ... }
    }
    

    Sample POST Body for Post1

    POST http://localhost:35979/api/books HTTP/1.1
    User-Agent: Fiddler
    Host: localhost:35979
    Content-Type: application/json; charset=utf-8
    Content-Length: 80
    
    {
        "Title":"Scary Book",
        "Author":"John Doe",
        "Genre":"Horror" 
    }
    

    Sample POST Body for Post2

    POST http://localhost:35979/api/books/alternate HTTP/1.1
    User-Agent: Fiddler
    Host: localhost:35979
    Content-Type: application/json; charset=utf-8
    Content-Length: 85
    
    {
        "Title":"Fantastic Book",
        "Author":"Jane Doe",
        "Genre":"Fantasy" 
    }