Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web API - 405 - The requested resource does not support http method 'PUT'

I have a Web API project and I am unable to enable "PUT/Patch" requests against it.

The response I get from fiddler is:


HTTP/1.1 405 Method Not Allowed
Cache-Control: no-cache
Pragma: no-cache
Allow: GET,POST,DELETE
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcUHJvamVjdHNcZG90TmV0XFdlYkFQSVxBZFNlcnZpY2VcQWRTZXJ2aWNlXGFwaVxpbXByZXNzaW9uXDE1?=
X-Powered-By: ASP.NET
Date: Tue, 06 May 2014 14:10:35 GMT
Content-Length: 72

{"message":"The requested resource does not support http method 'PUT'."}

Based on the above response, "PUT" verbs are not accepted. However, I'm unable to figure out where the related handler is configured.

The "Put" method of class is declared as follows:

[HttpPatch]
[HttpPut]
public HttpResponseMessage Put(Int32 aID, [FromBody] ImpressionModel impressionModel)
{
     bla, bla, bla, bla
}

I have read and implemented the changes explained in the following threads: - Asp.NET Web API - 405 - HTTP verb used to access this page is not allowed - how to set handler mappings - http://www.asp.net/web-api/overview/testing-and-debugging/troubleshooting-http-405-errors-after-publishing-web-api-applications

Nothing has worked as I'm still getting a 405 response when trying to issue a "PUT" command against my Web API project.

I even commented out all of the "Handlers" in the ApplicationsHost.config file.

Working with VS2012 Premium and IIS Express (I'm assuming it's version 8). I also tried the VS Dev Server but that gave me the same result also.

I'm out of ideas. Any help would be appreciated.

Thanks Lee

like image 310
LeeVDuhl Avatar asked May 06 '14 18:05

LeeVDuhl


6 Answers

Are you using attribute routing?

This mystic error was a route attributes issue. This is enabled in your WebAPIConfig as:

 config.MapHttpAttributeRoutes(); 

It turns out Web Api Controllers "cannot host a mixture of verb-based action methods and traditional action name routing. "; https://aspnetwebstack.codeplex.com/workitem/184

in a nutshell: I needed to mark all of my actions in my API Controller with the [Route] attribute, otherwise the action is "hidden" (405'd) when trying to locate it through traditional routing.

API Controller:

[RoutePrefix("api/quotes")]
public class QuotesController : ApiController
{
    ...

    // POST api/Quote
    [ResponseType(typeof(Quote))]
    [Route]
    public IHttpActionResult PostQuote(Quote quote)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        db.Quotes.Add(quote);
        db.SaveChanges();

        return CreatedAtRoute("", new { id = quote.QuoteId }, quote);
    }

note: my Route is unnamed so the CreatedAtRoute() name is just an empty string.

WebApiConfig.cs:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));

        // Web API routes
        config.MapHttpAttributeRoutes();

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

    }
}

hope this helps

like image 159
proggrock Avatar answered Nov 19 '22 14:11

proggrock


I had the exact same problem as you, and I tried all the things you tried but sometimes the solution is so trivial and under your nose, that you just don't expect it and keep looking for more complicated reasons. Make sure that in the url you're calling to test your web methods, the param names match the names in your controller method declaration. My 405 problem was solved by simply doing this (I was using query params):

My clientsController:

...

[HttpPut]
public string PutClient(string username = "", string phone= ""){...}

On my WebApiConfig:

// Web API routes
config.MapHttpAttributeRoutes();

config.Routes.MapHttpRoute(
     name: "DefaultApi",
     routeTemplate: "api/{controller}"
);

And the path used to test the method must be like so: (use Postman or similar, to apply the correct web method)

http://localhost:49216/api/clients?username=Kurt&phone=443332211

Otherwise, you'll get a 405 for that http method in that controller. I didn't need to change the web.config at all (no need to remove webdav, etc..). Check this for source in the documentation:

For example, consider the following action:

public void Get(int id)

The id parameter binds to the URI. Therefore, this action can only match a URI that contains a value for "id", either in the route dictionary or in the query string.

Optional parameters are an exception, because they are optional. For an optional parameter, it's OK if the binding can't get the value from the URI.

like image 25
kurt Avatar answered Nov 19 '22 15:11

kurt


This happened to me when I changed the first parameter name of the PUT method

public void Put(int code, [FromBody]Lead lead)

It should be:

public void Put(int id, [FromBody]Lead lead)

And this is how it gets called:

$.ajax({
    type: "PUT",
    data: json,
    url: "../api/leadsapi/123",
    contentType: "application/json; charset=utf-8"
});
like image 30
Daniel Cardenas Avatar answered Nov 19 '22 15:11

Daniel Cardenas


For me it was as many of the other posters had claimed. Chances are you have everything setup correctly in your webapiconfig, however you're just missing something silly.

In my case I had a route defined as:

[HttpPut]
    [Route("api/MilestonePut/{Milestone_ID}")]
    public void Put(int id, [FromBody]Milestone milestone)
    {
        db.Entry(milestone).State = System.Data.Entity.EntityState.Modified;
        db.SaveChanges();
    }

See the problem? The parameter is defined as Milestone_ID in the route, but as id in the function itself. You would think .NET would be smart enough to realize this, but it definitely isn't and will not work.

Once I changed it to match the parameter like so:

[HttpPut]
    [Route("api/MilestonePut/{id}")]
    public void Put(int id, [FromBody]Milestone milestone)
    {
        db.Entry(milestone).State = System.Data.Entity.EntityState.Modified;
        db.SaveChanges();
    }

everything worked like a charm.

like image 3
Indy-Jones Avatar answered Nov 19 '22 14:11

Indy-Jones


This is also the error message returned if you forget to make the Put() method on your API controller public. Which is obvious in hindsight, but caused me a good ten minutes of head-scratching.

like image 1
Dylan Beattie Avatar answered Nov 19 '22 14:11

Dylan Beattie


had the same problem, i needed to do 3 things to solve this:

  1. disable Webdav in <modules> and <handlers>
  2. Make sure that HttpPut is from System.Web.Http and not from System.Web.Mvc when using WebAPI
  3. enable ExtensionlessUrlHandler like this

<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />

<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />

<remove name="ExtensionlessUrlHandler-Integrated-4.0" />

<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />

<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />

<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />

Hope this can help some of you to solve this nasty issue...

like image 1
Ben Croughs Avatar answered Nov 19 '22 13:11

Ben Croughs