405 method not allowed Web API

This error is very common, and I tried all of the solutions and non of them worked. I have disabled WebDAV publishing in control panel and added this to my web config file:

  <handlers>
  <remove name="WebDAV"/>
  </handlers>
  <modules runAllManagedModulesForAllRequests="true">
  <remove name="WebDAVModule"/>
  </modules>

The error still persists. This is the controller:

   static readonly IProductRepository repository = new ProductRepository();

    public Product Put(Product p)
    {
        return repository.Add(p);
    }

Method implementation:

 public Product Add(Product item)
    {
        if (item == null)
        {
            throw new ArgumentNullException("item");
        }
        item.Id = _nextId++;
        products.Add(item);
        return item;
    }

And this is where the exception is thrown:

client.BaseAddress = new Uri("http://localhost:5106/");
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));      
var response = await client.PostAsJsonAsync("api/products", product);//405 exception

Any suggestions?


Solution 1:

You are POSTing from the client:

await client.PostAsJsonAsync("api/products", product);

not PUTing.

Your Web API method accepts only PUT requests.

So:

await client.PutAsJsonAsync("api/products", product);

Solution 2:

I had the same exception. My problem was that I had used:

using System.Web.Mvc; // Wrong namespace for HttpGet attribute !!!!!!!!!
[HttpGet]
public string Blah()
{
    return "blah";
}

SHOULD BE

using System.Web.Http; // Correct namespace for HttpGet attribute !!!!!!!!!
[HttpGet]
public string Blah()
{
    return "blah";
}

Solution 3:

I tried many thing to get DELETE method work (I was getting 405 method not allowed web api) , and finally I added [Route("api/scan/{id}")] to my controller and was work fine. hope this post help some one.

     // DELETE api/Scan/5
    [Route("api/scan/{id}")]
    [ResponseType(typeof(Scan))]
    public IHttpActionResult DeleteScan(int id)
    {
        Scan scan = db.Scans.Find(id);
        if (scan == null)
        {
            return NotFound();
        }

        db.Scans.Remove(scan);
        db.SaveChanges();

        return Ok(scan);
    }

Solution 4:

My problem turned out to be Attribute Routing in WebAPI. I created a custom route, and it treated it like a GET instead of WebAPI discovering it was a POST

    [Route("")]
    [HttpPost] //I added this attribute explicitly, and it worked
    public void Post(ProductModel data)
    {
        ...
    }

I knew it had to be something silly (that consumes your entire day)

Solution 5:

Chrome often times tries to do an OPTIONS call before doing a post. It does this to make sure the CORS headers are in order. It can be problematic if you are not handling the OPTIONS call in your API controller.

public void Options() { }