Asp.Net Core 3.1 405 Method Not Allowed - c#

Hi Guys I need help.. I always get 405 Method Not Allowed
I'm using Asp.Net Core Web Application 3.1, I dont have problem with HttpGet but when i use HttpPost it always return 405 Status Code
Here is the My Controller
[Route("api/[controller]")]
[ApiController]
public class ExamController : ControllerBase
{
[HttpPost("PostValue")]
public ActionResult<HttpResponseMessage> PostInfo([FromBody] PersonalInfo info)
{
string json = JsonConvert.SerializeObject(info);
HttpClient client = new HttpClient();
var response = client.PostAsync("https://sampleapi/receive", new StringContent(json, Encoding.UTF8, "application/json"));
if (response.IsFaulted)
return BadRequest(response);
return Ok(response);
}
}
This is my Startup Class
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddCors(c =>
{
c.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin());
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStatusCodePages();
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseCors(options => options.AllowAnyOrigin());
}
Here is the sample image of URL and the Result

Looking at the provided image, you use chrome to issue the url request, which is a HTTP GET command. So, your app got an HTTP GET command but your method wants to accept an HTTP POST method. That's why it says 'method not allowed'.
If you want to try http commands, you need a web test tool such as PostMan.

Configure the CORS middleware properly. Add .AllowAnyMethod() after options.AllowAnyOrigin() as a chain. You may end up to this for testing purposes: app.UseCors(x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
As another option, make sure that your web server (likely IIS) allows POST HTTP method besides GET.

In addition to the postman test method, another way to test the post request is to use ajax to send post request in jquery, here is a sample:
<script>
$(function () {
$("#send").click(function () {
var personalInfo = { Id: $('#Id').val(), Name: $('#Name').val() };
$.ajax({
url: 'http://localhost:50855/api/Exam/PostValue',
type: 'POST',
contentType: "application/json; charset=utf-8",
dataType: 'json',
data: JSON.stringify(personalInfo),
//success: function (data, textStatus, xhr) {
// console.log(data);
//},
//error: function (xhr, textStatus, errorThrown) {
// console.log('Error in Operation');
//}
});
});
})
</script>
<form id="form1">
Id : <input type="text" name="Id" id="Id" />
Name: <input type="text" name="Name" id="Name" />
<input type="button" id="send" value="Send Post Data" />
</form>
Here is the test result:

I'm just going to add to this thread with my issue and resolution to same in case someone else stumbles upon this.
I was receiving a 405 error code, despite the action being decorated with the HttpPost and ValidateAntiForgeryToken attributes, and ensuring the posted form data included the anti-forgery token. Everything worked fine locally, but as soon as I put everything up on the server that's when I started receiving the 405 error. Turns out this error had nothing to do with what I had done in my app. It was actually an issue in a stored procedure in my MySQL database. Locally, case sensitivity isn't an issue, but on the server I had upper-cased the name of a table that was in lower-case, which caused an error to bubble up and give me this very obscure 405 error.
I guess lesson learned here is to check EVERYTHING :)
Edit: For clarity, my issue relates to MySQL and Linux Hosting. Not sure if same would apply if using Windows hosting solutions

My solution was literally as stupid as adding a "/" to the end of my request URL. Lost hours over it. GET worked fine without it.

I am working on .Net 5 Api project, and came across this same issue.
Adding lines below to the auto-generated web.config file when release is done:
<modules>
<remove name="WebDAVModule" />
</modules>
to the <system.webServer> part of web.config and
<handlers>
<remove name="WebDAV" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,PUT,DELETE,DEBUG" type="System.Web.Handlers.TransferRequestHandler" resourceType="Unspecified" requireAccess="Script" preCondition="integratedMode,runtimeVersionv4.0" responseBufferLimit="0" />
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
fixed it for me. Some of the lines are probably a bit of an overkill, but I have philosophy "if it may not work in future, better to have it overengineered".
However, I was struggling a lot with Azure DevOps CI-CD pipelines.
I managed to do it, and wrote about how I did it here:
Azure DevOps Release Pipeline Web.Config Edit

Okay so I've been reading about removing the WebDav by entering in the web.config but that didn't work for me for core 3.1. What you need to do is remove it from the IIS by:
Expand the server in IIS 8
Select the site
Click on handling mappings (For the site not server)
Search for WebDav and remove it.
Restart IIS
Web.config should be left alone. when i added the remove name=WebDav, my API stopped working.
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
note: you may need to also remove the one from the server if that doesn't work as I removed that first when I was troubleshooting.

Add [Route("MethodName")] in the header of the method in the controller. Just like:
[Route("api/[controller]")]
[ApiController]
public class AccountController : Controller
{
[Route("getusers")]
public async Task<User> GetUsers()
{
...
}
}

Related

.Net Core 2.2 Web API 405

I am trying to setup a .net core 2.2 web api to use a post verb. Anything other than a get verb returns a 405 no matter if it is run on my local machine (w10 iis eXPRESS 10.0) or the windows server (2016 R2 IIS 8.0). I've read the other posts about disabling WebDav in your config file, adding a route, and completely removing the WebDav feature. I have done all of those to no avail. I'm just starting to develop in core and find this baffling, on the same server is a non-core web api that runs on .net framework 4.5 that processes GET,PUT,POST,DELETE without error. And yes, I have restarted the server after making changes to any of the configurations. The following are the web.config changes that I made, the last one coming directly from MS. Basic project that reproduces the same error on my machine and server is here https://github.com/FranciscanMedia/error405_core/tree/master it is just a standard web api project you get when you fire up VS2019.
<system.webServer>
<handlers accessPolicy="Read, Script">
<remove name="WebDAV" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<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" />
</handlers>
</system.webServer>
<system.webServer>
<modules>
<remove name="WebDAVModule" />
</modules>
<handlers>
<remove name="WebDAV" />
</handlers>
</system.webServer>
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<modules runAllManagedModulesForAllRequests="false">
<remove name="WebDAVModule"/>
</modules>
</system.webServer>
<system.webServer>
<handlers accessPolicy="Read, Script">
<remove name="WebDAV" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<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" />
</handlers>
</system.webServer>
Short answer
It could be as simple as that. The reason is routing.
Just send your POST request to right URL like https://localhost:44327/api/values/123.
Detailed explanation
It's not the issue. It works as expected.
You make a GET request to https://localhost:44327/api/values/. It returns 200 OK.
But when you make a POST request to the same URL https://localhost:44327/api/values/. It says 405 Method not allowed.
However, you get 405. It is happening because you are hitting the GET endpoint with POST method.
Microsoft Docs says:
... the HTTP client sent a valid JSON request to the URL for a Web API application on a web server, but the server returned an HTTP 405 error message which indicates that the PUT method was not allowed for the URL. In contrast, if the request URI did not match a route for the Web API application, the server would return an HTTP 404 Not Found error.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/testing-and-debugging/troubleshooting-http-405-errors-after-publishing-web-api-applications
If you simply remove the GET endpoint. The POST request will start returning 404 Not found. Which means that you are not hitting any registered route.
To send POST request you need to use different URL according to the routing rules.
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// POST api/values
[HttpPost("{val}")]
public StatusCodeResult Post()
{
return Ok();
}
}
This attribute-based configuration means that route of your POST endpoint is /api/Values/{val}. Where {val} is any value. It's not processed in the endpoint.
If you want to process it, you should pass it to the method:
[HttpPost("{val}")]
public StatusCodeResult Post(string val)
{
return Ok();
}
I think that in your controller you have to import another library.
Try
using System.Web.Http;
Instead of
using Microsoft.AspNetCore.Mvc
Looking at what you have defined:
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
Then for the action:
[HttpPost("{val}")]
public StatusCodeResult Post()
{
return Ok();
}
Your routing matches the following url:
https://localhost:44327/api/values/StatusCodeResult
It is going to take your main route defined on your controller [Route("api/[controller]")]
Then you are defining the "template" to use "{val}"
This is telling it to use the ActionResult specific name and to expect var val to be passed/appened.
Checking out the official documentation here: https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/routing?view=aspnetcore-2.2
under section "Token replacement in route templates ([controller], [action], [area])"
They specifiy:
For convenience, attribute routes support token replacement by enclosing a token in square-braces ([, ]). The tokens [action], [area], and [controller] are replaced with the values of the action name, area name, and controller name from the action where the route is defined. In the following example, the actions match URL paths as described in the comments:
[Route("[controller]/[action]")]
public class ProductsController : Controller
{
[HttpGet] // Matches '/Products/List'
public IActionResult List() {
// ...
}
[HttpGet("{id}")] // Matches '/Products/Edit/{id}'
public IActionResult Edit(int id) {
// ...
}
}
If you want it to just route based on just verbs (follow a pattern where each api endpoint just handles operations for that specific object) then you would change your post method to just
[HttpPost]
public ActionResult Post(string val)
{
return Ok();
}
I totally agree with #Vladimir's answer. I dont have enough points to add comments to the answer by #vlaimir so i am adding my thoughts and suggestions.
The code you have on your github,
// POST api/values
[HttpPost("{val}")]
public StatusCodeResult Post()
{
return Ok();
}
This is a post and it would expect a value {val} per the route action configuration. Since you may try to hit the post without any value, thats not permitted. Ensure you supply some value and then do the POST. If you are using POSTMAN, you may have to supply the BODY of your request with some value. Swagger is a great util tool to embed into the web api's and that comes with excellent intuitive UI for our routes/resources. That might be even ideal to help determine and ensure you supply the right value.
Otherwise, you dont need to modify or worry about your IIS or IIS Express settings. or webdav.

Asp.net core web api using windows authentication - Cors request unauthorised

In my asp.net core web api, I've configured Cors as per the article from MS documentation. The web api app is using windows authentication (Anonymous Authentication is Not enabled). Cor's policy is created and middle ware is added as below in the startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.WithOrigins("http://localhost:4200")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
);
});
services.AddMvc().AddJsonOptions(options => {
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//Enable CORS policy
app.UseCors("CorsPolicy");
app.UseMvc();
}
Also applied the policy per controller level
[EnableCors("CorsPolicy"), Route("api/[controller]")]
public class LocationController : BaseController<Location>
{
//code
}
Options request is getting Unauthorized. The request & response looks like
I have seen similar questions and tried almost every solution but the options request is still failing.
1) Set Allow Windows, and anonymous Authentication flag to true in launchSettings.json file (Development settings file).
Anonymous Authentication: is needed to allow Pre flight option request.
{
"iisSettings": {
"windowsAuthentication": true,
"anonymousAuthentication": true,
"iis":
...
}
2) Add Cors Policy in Configure service method.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddCors(options =>
{
options.AddPolicy("MyCustomCorsPolicyName",
builder => builder.WithOrigins("http://YourDomainName/")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
);
});
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
3: Adds a CORS middleware to your web application pipeline to allow cross domain requests.
public void Configure(IApplicationBuilder app)
{
....
app.UseCors("MyCustomCorsPolicyName");
app.UseMvc();
}
4) Add Authorize Attribute on top of your controller to Force, client to send credentials
[Authorize]
public class MyAPIController : ControllerBase
{
...
}
5) In JQuery or any client that you are using set withCredentials property flag to true
$.ajax({
type: "POST",
datatype: "json",
url: "YourApiUrl",
xhrFields: {
withCredentials: true
}
This worked for me in my development environment using .net core 2.2, IIS Express with Windows Authentication.
You may want to read this thread: https://github.com/aspnet/CORS/issues/60. You can mix anonymous and NTLM so that your CORS preflights aren't denied (since they don't include windows credentials). IIS handles NTLM authentication before it even gets to the middleware so this is probably an IIS thing. You may need to allow anonymous CORs preflight checks.
Using IIS CORS Module solved the problem superbly. Below URL is for reference.
Working with Windows Authentication
While this is by no means the only scenario solved by the CORS module, it was important enough to warrant calling out. Previously, if you tried to make a cross-domain request to an application that used Windows Authentication, your preflight request would fail since the browser did not send credentials with the preflight request. There was no way to work around this without enabling anonymous authentication in your application. Since the CORS module kicks in before authentication, it makes it possible to handle a pre-flight request without compromising on the security model of your application. Here's an example of what your web.config might look like.
https://blogs.iis.net/iisteam/getting-started-with-the-iis-cors-module
Sample Code:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- To customize the asp.net core module uncomment and edit the following section.
For more info see https://go.microsoft.com/fwlink/?linkid=838655 -->
<system.web>
<authentication mode="Windows"/>
</system.web>
<system.webServer>
<cors enabled="true" failUnlistedOrigins="true">
<add origin="http://localhost:60096" allowCredentials="true" >
<allowHeaders allowAllRequestedHeaders="true">
<add header="Header1" />
</allowHeaders>
</add>
</cors>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="dotnet" arguments=".\Project.Api.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" />
</system.webServer>
</configuration>
This is very similar to CORS enabled but response for preflight has invalid HTTP status code 404 when POSTing JSON and provided solution working for me(I had 401 error on POST requests). Also NTLM and Negotiate should not be configured both(Negotiate V/s NTLM).
It looks like you want pass credential or along with request.
Please Check this link for add credential / allow user credential.
Be careful when allowing cross-origin credentials. A website at another domain can send a logged-in user's credentials to the app on the user's behalf without the user's knowledge. The CORS specification also states that setting origins to "*" (all origins) is invalid if the Access-Control-Allow-Credentials header is present.
After a couple hours figuring it out, here is a COMPLETE solution (front-end to back-end):
My problem: When I enabled the windows authentication on my web API, I could not do fetch calls from my react app to my .NET Core 3.1 web API, CORS was freaking out. With Anonymous authentication it worked, but not when windows authentication is enabled.
1.launchSettings.json
this will be used only for your dev environnment, make sure windows auth is also enabled in IIS on your prod server.
{
"iisSettings": {
"windowsAuthentication": true,
"anonymousAuthentication": false,
"iisExpress": {
"applicationUrl": "http://localhost:58747",
"sslPort": 0
}
},
{... more settings if any}
}
2.Startup.cs:
CORS policy is enabled here. The order of methods is important here. Also, you don't need to set those in a web.config
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", //give it the name you want
builder =>
{
builder.WithOrigins( "http://localhost:3000", //dev site
"production web site"
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
//database services here
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
// global policy same name as in the ConfigureServices()
app.UseCors("CorsPolicy");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
3.Controller(s):
using Microsoft.AspNetCore.Cors;
... your other usings
namespace ProjectTest.Controllers
{
[ApiController]
[EnableCors("CorsPolicy")] //THIS HERE needs to be the same name as set in your startup.cs
[Route("[controller]")]
public class FooController:Controller
{
[HttpGet("getTest")]
public JsonResult GetTest()
{
return Json("bar");
}
}
}
4.React Component fetch call example:
The "credential: 'include'" is the secret
await fetch('http://localhost:3000/Foo/getTest', {
method: 'GET',
credentials: 'include'
}).then(resp => resp.json());
Just a note CORS middleware doesn't work in IIS see this thread here
Install CORS module in IIS
Transform your web.config (btw I'm using .net core 3.1)
Add a web.release.config on the root of your app
Follow this XML code
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<system.web xdt:Transform="Insert">
<authentication mode="Windows"/>
</system.web>
<system.webServer xdt:Transform="Insert">
<cors enabled="true" failUnlistedOrigins="true" >
<add origin="your origin" allowCredentials="true" >
<allowHeaders allowAllRequestedHeaders="true">
<add header="your header" />
</allowHeaders>
</add>
</cors>
</system.webServer>
</configuration>
Deploy your app in IIS

"The requested resource does not support http method 'OPTIONS'" when using EnableCors

I want to enable CORS on one specific action in an Asp.net Web Api. Here's how I'm trying to do it:
[Route("api/mycontroller/myaction")]
[HttpPost]
[EnableCors("https://example.com", "*", "post")]
public async Task<IHttpActionResult> MyAction()
{
...
}
But when I send an OPTIONS request to the route, I get back an error: "The requested resource does not support http method 'OPTIONS'." I also tried removing the [HttpPost] annotation to no avail.
What am I missing?
For me, I added the following headers to the request by adding the following code to the Application_BeginRequest function of the Global.asax.cs file:
protected void Application_BeginRequest()
{
if (Request.Headers.AllKeys.Contains("Origin", StringComparer.CurrentCultureIgnoreCase)
&& Request.HttpMethod == "OPTIONS")
{
Response.AddHeader("Access-Control-Allow-Headers", "content-type", "accept", "pragma", "cache-control", "authorization");
Response.End();
}
}
I have little idea why this works.
Out of curiosity, I tried adding all headers by using an asterisk but then Web API complained that the Authorization header was missing.
You've probably missed the higher level call to HttpConfiguration.EnableCors, as described here: https://enable-cors.org/server_aspnet.html.
Add this code to your configuration:
public static void Register(HttpConfiguration config)
{
// New code
config.EnableCors();
}
To ensure the OPTIONS request gets handled by your application code and not some other part of the system before it reaches your app code, you may try adding the following to your web.config:
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
You might also need to include:
<add name="OPTIONSVerbHandler" path="*" verb="OPTIONS"
modules="IsapiModule" requireAccess="None"
scriptProcessor="C:\Windows\System32\inetsrv\asp.dll"
resourceType="Unspecified" />
See the answer at IIS hijacks CORS Preflight OPTIONS request.
Or maybe even just this:
<add name="OPTIONSVerbHandler" path="*" verb="OPTIONS"
modules="ProtocolSupportModule" requireAccess="None" />
If none of that on its own works, then in your global.asax or other code you might try:
if (filterContext.HttpContext.Request.HttpMethod == "OPTIONS")
{
filterContext.HttpContext.Response.Flush();
}
…or some other variation on that, for example:
if (Request.Headers.AllKeys.Contains("Origin", StringComparer.OridinalIgnoreCase)
&& Request.HttpMethod == "OPTIONS") {
Response.Flush();
}
Regardless of what specific code you use to do it, the point is to:
make sure OPTIONS requests are actually getting caught/handled by your application code—not caught/handled by some other part of the system before ever reaching your app code
make sure you have explicit handling for OPTIONS requests in your application code
make the OPTIONS handling in your application code just do Response.Flush()
Or another approach I’m not sure is relevant to your situation as coded but I’ll mention just in case:
public HttpResponseMessage Options()
{
var response = new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK
};
return response;
}

CORS headers not being set when using dot (".") in query string

I'm having a strange and weird situtation here.
If I send a request to: /scenes/?lang=es-ar, the headers are set just fine and everything seems OK.
However, if I send one to: /scenes/?lang=es-ar&sort.asc=creation, the headers are missing and I'm unable to fetch the response due to cross origin.
CORS is automatically managed by Owin's CORS Middleware, so this is out of my hands.
Here is my middleware's configuration:
private void ConfigureCors(IAppBuilder application)
{
CorsPolicy policy = new CorsPolicy()
{
AllowAnyHeader = true,
AllowAnyOrigin = true,
SupportsCredentials = true,
};
policy.Methods.Add("GET");
policy.Methods.Add("POST");
policy.Methods.Add("PUT");
policy.Methods.Add("DELETE");
policy.Methods.Add("OPTIONS");
policy.ExposedHeaders.Add("Location");
application.UseCors(new CorsOptions()
{
PolicyProvider = new CorsPolicyProvider()
{
PolicyResolver = request => System.Threading.Tasks.Task.FromResult(policy)
}
});
}
Why are the headers not being sent on the response?
I'm guessing it has something to with the "." (dot) in sort.asc=creation
I'm using latest version of ASP.NET Web Api (5.2.3) and Microsoft.Owin.Cors (3.0.1)
There might be a possibility that hosting server IIS might be intercepting the pre-flight requests. To ensure ASP.NET handles OPTION requests, add the following in web.config:
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
In my opinion this is not a decent choice to use Microsoft.Owin.Cors with WebAPI, if you're planning to use IIS as hosting environment. A better choice for Asp.net WebAPi would be Asp.net web API implementation of CORS.

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
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
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.
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"
});
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.
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.
had the same problem, i needed to do 3 things to solve this:
disable Webdav in <modules> and <handlers>
Make sure that HttpPut is from System.Web.Http and not from System.Web.Mvc when using WebAPI
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...
This answer fixed the issue for me. I had to add the Route attribute and the problem was solved.
[HttpPut]
[Route("")]
public HttpResponseMessage MyMethod()
You should configure it in your webservers config. It depends on the type of the webserver, where your can do it. For example by IIS, you can use a web.config file to do that in your document root. By cross-origin requests you have to add CORS headers to the response, to allow origins, methods, etc...
note: Probably you can do something about this with the ASP.NET framework as well, but I think it's unlike.
Add the following section under Handler section in web.config:
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,POST,PUT,PATCH,MERGE" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
For instance:
<handlers>
<remove name="WebDAV" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,POST,PUT,PATCH,MERGE" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
Maybe it's late now, but someone can use this.
I wanted to use PUT request and I just sent stringified object to web api and in put method only accepted that object.
JQUERY
let musterija = {
Name: name,
Email: email,
Password: password,
Username: logUser.Username,
Lastname: lastname,
GenderString: gender,
Jmbg: identification,
PhoneNumber: phone,
};
$.ajax({
method: "PUT",
url: "/api/Musterija",
data: JSON.stringify(musterija),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function () {
alert("Entity updated");
EmptyAllInputs();
$('#divprofile').show();
$('#divupdate').hide();
},
error: function (msg) {
alert("Fail - " + msg.responseText);
}
});
WEB API
[HttpPut]
public HttpResponseMessage PutMusterija(Musterija m)

Categories