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?
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);
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";
}
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)
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);
}
This error can also occur when you try to connect to http while the server is on https.
It was a bit confusing because my get-requests were OK, the problem was only present with post-requests.
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() { }
I'm late to this party but as nothing above was either viable or working in most cases, here is how this was finally resolved for me.
On the server the site/service was hosted on, a feature was required!
HTTP ACTIVATION!!!
Server Manager > Manage > Add Roles and Features > next next next till you get to Features > Under .NET (each version) tick HTTP Activation.
Also note there is one hidden under >net > WCF Services.
This then worked instantly!
That was melting my brain
I was getting the 405 on my GET call, and the problem turned out that I named the parameter in the GET server-side method Get(int formId), and I needed to change the route, or rename it Get(int id).
You can also get the 405 error if say your method is expecting a parameter and you are not passing it.
This does NOT work ( 405 error)
HTML View/Javascript
$.ajax({
url: '/api/News',
//.....
Web Api:
public HttpResponseMessage GetNews(int id)
Thus if the method signature is like the above then you must do:
HTML View/Javascript
$.ajax({
url: '/api/News/5',
//.....
If you have a route like
[Route("nuclearreactors/{reactorId}")]
You need to use the exact same parameter name in the method e.g.
public ReactorModel GetReactor(reactorId)
{
...
}
If you do not pass the exact same parameter you may get the error "405 method not allowed" because the route will not match the request and WebApi will hit a different controller method with different allowed HTTP method.
This does not answer your specific question, but when I had the same problem I ended up here and I figured that more people might do the same.
The problem I had was that I had indeliberately declared my Get method as static. I missed this an entire forenoon, and it caused no warnings from attributes or similar.
Incorrect:
public class EchoController : ApiController
{
public static string Get()
{
return string.Empty;
}
}
Correct:
public class EchoController : ApiController
{
public string Get()
{
return string.Empty;
}
}
Here is one solution:
<handlers accessPolicy="Read, Script">
<remove name="WebDAV" />
</handlers>
learn.microsoft.com solution article
and remove WebDAV from modules
<remove name="WebDAVModule" />
[HttpPost] is unnecessary!
[Route("")]
public void Post(ProductModel data)
{
...
}
I could NOT solve this. I had CORS enabled and working as long as the POST returned void (ASP.NET 4.0 - WEBAPI 1). When I tried to return a HttpResponseMessage, I started getting the HTTP 405 response.
Based on Llad's response above, I took a look at my own references.
I had the attribute [System.Web.Mvc.HttpPost] listed above my POST method.
I changed this to use:
[System.Web.Http.HttpPostAttribute]
[HttpOptions]
public HttpResponseMessage Post(object json)
{
...
return new HttpResponseMessage { StatusCode = HttpStatusCode.OK };
}
This fixed my woes. I hope this helps someone else.
For the sake of completeness, I had the following in my web.config:
<httpProtocol>
<customHeaders>
<clear />
<add name="Access-Control-Expose-Headers " value="WWW-Authenticate"/>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS, PUT, PATCH, DELETE" />
<add name="Access-Control-Allow-Headers" value="accept, authorization, Content-Type" />
<remove name="X-Powered-By" />
</customHeaders>
</httpProtocol>
Old question but none of the answers worked for me.
This article solved my problem by adding the following lines to web.config:
<system.webServer>
<modules runAllManagedModulesForAllRequests="false">
<remove name="WebDAVModule" />
</modules>
</system.webServer>
In my case I had a physical folder in the project with the same name as the WebAPI route (ex. sandbox) and only the POST request was intercepted by the static files handler in IIS (obviously).
Getting a misleading 405 error instead of the more expected 404, was the reason it took me long to troubleshoot.
Not easy to fall-into this, but possible. Hope it helps someone.
Make sure your controller inherits from Controller class.
It might even be crazier that stuff would work locally even without that.
For my part my POST handler was of this form:
[HttpPost("{routeParam}")]
public async Task<ActionResult> PostActuality ([FromRoute] int routeParam, [FromBody] PostData data)
I figured out that I had to swap the arguments, that is to say the body data first then the route parameter, as this:
[HttpPost("{routeParam}")]
public async Task<ActionResult> PostActuality ([FromBody] PostData data, [FromRoute] int routeParam)
check in your project .csproj file and change
<IISUrl>http://localhost:PORT/</IISUrl>
to your website url like this
<IISUrl>http://example.com:applicationName/</IISUrl>
Another possible issue which causes the same behavior is the default parameters in the routing. In my case the controller was located and instantiated correctly, but the POST was blocked because of default Get action specified:
config.Routes.MapHttpRoute(
name: "GetAllRoute",
routeTemplate: "api/{controller}.{ext}"/*,
defaults: new { action = "Get" }*/ // this was causing the issue
);
I was having exactly the same problem. I looked for two hours what was wrong with no luck until I realize my POST method was private instead of public .
Funny now seeing that error message is kind of generic. Hope it helps!
We had a similar issue. We were trying to GET from:
[RoutePrefix("api/car")]
public class CarController: ApiController{
[HTTPGet]
[Route("")]
public virtual async Task<ActionResult> GetAll(){
}
}
So we would .GET("/api/car") and this would throw a 405 error.
The Fix:
The CarController.cs file was in the directory /api/car so when we were requesting this api endpoint, IIS would send back an error because it looked like we were trying to access a virtual directory that we were not allowed to.
Option 1: change / rename the directory the controller is in
Option 2: change the route prefix to something that doesn't match the virtual directory.
In my case, the 405 error only showed up in production server, and not on my dev machine.
I found that the problem was due to the fact that I simply "manually" transferred the contents of the locally published folder from my local machine to the online production server.
So, the FIX for me was to simply delete all the online files on the prod server, and then use the "Publish" option on Visual Studio to publish directly from my local machine to the prod server via FTP.
I don't know exactly why this changed something, because it seems to me the files were the same, but this thing fixed the problem and I hope it could help someone else too.
Another possible cause can be to do with Session State config in IIS causing a redirect which appends "?AspxAutoDetectCookieSupport=1" to the URL. In my case I was performing a POST but the redirect was being performed as a GET by the HttpClient.
The solution I found was to add the following to my web.config:
<system.web>
<sessionState cookieless="UseCookies" />
</system.web>
Function names make it complicated for c# sometimes. Change name of the function, it will works. Like ProductPut instead of PutProduct or Put.
public Product ProductPut(Product p)
{
return repository.Add(p);
}
Related
My home controller sucessfully return index.html from
http://localhost/
and
http://localhost/controller/
but if i try to hit
http://localhost/controller/method/
I get a 404 even though that method works fine in IIS express.
Couldn't find anything online with someone having a similar issue where only the methods on a controller didn't work on one particular deployment but the controller itself is fine.
Things I've Tried that were common among a lot of .Net Core 2.0 issues with IIS Deployments:
Make sure windows authentication is on in project settings and in IIS (I've toggled it on and off to no avail on both I don't have user auth on my web app so I don't think this matters for me).
Switched my application pool to use No managed code for CLR version
Change application pool ID to be LocalSystem
Change permissions on my publish output folder to include %hostname%\IIS_IUSRS
Pretty sure I've also tried a lot of other basic troubleshooting that sometimes fixes issues. I.E. removing and readding app. Turning things on and off again to no avail.
Any suggestions how to troubleshoot this would be very welcome.
I also want to note it was working yesterday and can't remember changing anything other than the publishing output to use Debug instead of Release which of course by now I've changed back to Release but still no luck.
Here is some code
public class MyController : Controller
{
public IActionResult Index()
{
return View();
}
[HttpPost]
public void Store([FromBody]MyObject obj)
{
Console.WriteLine(Request.Body);
//Some code
}
[HttpGet]
public void Check(string objectUID, string idfv)
{
Console.WriteLine($"ObjectUID: {objectUID}");
Console.WriteLine($"IDFV: {idfv}");
//some other code
}
[HttpGet]
public MyObject Retrieve(string objectUID)
{
Console.Writeline($"ObjectUID: {objectUID}");
//Some Code
}
}
This is my routing.
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=MyController}/{action=Index}/{id?}");
});
If you‘re not sure why it doesn’t work, try Attribute-Routing, explained in the Docs
Then you could try it this way:
[Route("[controller]/[action]")]
public class MyController : Controller
{
public IActionResult Index()
{
return View();
}
[HttpPost]
public void Store([FromBody]MyObject obj)
{
Console.WriteLine(Request.Body);
//Some code
}
// If you have a parameter from the uri or query-string, you can add it to the Template this way
[HttpGet("{objectUID} ")]
public void Check(string objectUID, string idfv)
{
Console.WriteLine($"ObjectUID: {objectUID}");
Console.WriteLine($"IDFV: {idfv}");
//some other code
}
// Or optional parameter like this
[HttpGet ("{objectUID?} ")]
public MyObject Retrieve(string objectUID)
{
Console.Writeline($"ObjectUID: {objectUID}");
//Some Code
}
}
Since you are getting 404 error, I suspect the aspnet core handler is missing from your website. Assuming that you have .NET Core Hosting Bundle installed,
ensure you have the following handler added in the web.config file. If web.config file is missing add a new web.config. Also, add a logs folder at the website root folder for logging.
<?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.webServer>
<handlers>
<remove name="aspNetCore"/>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
</handlers>
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" />
</system.webServer>
</configuration>
I got ASP.NET Core 2 app running on my machine following these steps:
App Pool setting run under AppPoolIdentity with No Managed runtime configuration
Publish your ASP.NET Core 2 website to a folder. By default it publishes to bin\Release\PublishOutput
Point your IIS website to published folder
I was having a similar issue with getting a 404 when trying to access my site's Account controller. All of the other Razor pages where working correctly. If I change the inheritInChildApplications="false" to true in the web.config the controller starts working.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="true">
...
</configuration>
I have an ASP.NET Web API running locally on some port and I have an angularjs app running on 8080. I want to access the api from the client.
I can successfully login and register my application because in my OAuthAuthorizationProvider explicitly sets the repsonse headers in the /Token endpoint.
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
That's good. However, my other API methods do not seem to work. In my WebApiCongig.Register, I enable CORS and I add the EnableCors Attribute to my controllers to allow all origins, all headers, and all methods. I can set a break point in my get method on the controller and it gets hit just fine. Here is what I found watching the Network tab in chrome.
2 requests are are sent to the same api method. One method type OPTIONS and one with method type GET. The OPTIONS request header includes these two lines
Access-Control-Request-Headers:accept, authorization
Access-Control-Request-Method:GET
And the response includes these lines
Access-Control-Allow-Headers:authorization
Access-Control-Allow-Origin:*
However, the GET method request looks quite different. It returns ok with a status code of 200, but it does not inlcude and access control headers in the request or response. And like I said, it hits the API just fine. I can even do a POST and save to the database, but the client complains about the response!!
I've looked at every single SO question and tried every combination of enabling cors. I'm using Microsoft.AspNet.Cors version 5.2.2. I'm' using AngularJS version 1.3.8. I'm also using the $resource service instead of $http which doesn't seem to make a difference either.
If I can provide more information, please let me know.
BTW, I can access the Web API using Fiddler and/or Postman by simply including the Bearer token.
You don't seem to be handling the preflight Options requests.
Web API needs to respond to the Options request in order to confirm that it is indeed configured to support CORS.
To handle this, all you need to do is send an empty response back. You can do this inside your actions, or you can do it globally like this:
protected void Application_BeginRequest()
{
if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
{
Response.Flush();
}
}
This extra check was added to ensure that old APIs that were designed to accept only GET and POST requests will not be exploited. Imagine sending a DELETE request to an API designed when this verb didn't exist. The outcome is unpredictable and the results might be dangerous.
Also I suggest enabling Cors by web.config instead of config.EnableCors(cors);
This can be done by adding some custom headers inside the <system.webServer> node.
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
Please note that the Methods are all individually specified, instead of using *. This is because there is a bug occurring when using *.
This ended up being a simple fix. Simple, but it still doesn't take away from the bruises on my forehead. It seems like the more simple, the more frustrating.
I created my own custom cors policy provider attribute.
public class CorsPolicyProvider : Attribute, ICorsPolicyProvider
{
private CorsPolicy _policy;
public CorsPolicyProvider()
{
// Create a CORS policy.
_policy = new CorsPolicy
{
AllowAnyMethod = true,
AllowAnyHeader = true,
AllowAnyOrigin = true
};
// Magic line right here
_policy.Origins.Add("*");
}
public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return Task.FromResult(_policy);
}
}
I played around with this for hours. Everything should work right?? I mean the EnableCors attribute should work too?? But it didn't. So I finally added the line above to explicitly add the origin to the policy. BAM!! It worked like magic. To use this just add the attribute to your api class or method you want to allow.
[Authorize]
[RoutePrefix("api/LicenseFiles")]
[CorsPolicyProvider]
//[EnableCors(origins: "*", headers: "*", methods: "*")] does not work!!!!! at least I couldn't get it to work
public class MyController : ApiController
{
in my case, after I changed the Identity option of my AppPool under IIS from ApplicationPoolIdentity to NetworkService, CORS stopped working in my app.
I am specifying a custom route and an action. What am I doing wrong? I am getting a 404 error. I set it up similar to this example:
http://www.codeproject.com/Articles/190267/Controllers-and-Routers-in-ASP-NET-MVC
URL:
http://localhost:14133/ScanSummary/mywebsite.com
Route:
routes.MapRoute(
"ScanSummary",
"ScanSummary/{domain}",
new { controller = "ScanSummary", action = "Get" }
);
Controller:
public class ScanSummaryController : Controller
{
public ActionResult Get(string domain)
{
return View();
}
}
Because of the .com extension, IIS thinks that this is a file on the disk and attempts to serve it directly instead of going through the pipeline.
One way to fix the issue is by running managed modules for all requests:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
...
</system.webServer>
Another (and IMHO better way) is to explicitly map the MVC handler to this endpoint:
<system.webServer>
<modules runAllManagedModulesForAllRequests="false" />
<handlers>
...
<add
name="SvanSummaryHandler"
path="ScanSummary/*"
verb="GET,HEAD,POST"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
Also I would recommend you reading the following blog post to better understand the gotchas that are awaiting you if you intend to be passing arbitrary characters in the path portion of an URL: http://www.hanselman.com/blog/ExperimentsInWackinessAllowingPercentsAnglebracketsAndOtherNaughtyThingsInTheASPNETIISRequestURL.aspx
And simply follow what Scott Hanselmann suggests:
After ALL this effort to get crazy stuff in the Request Path, it's
worth mentioning that simply keeping the values as a part of the Query
String (remember WAY back at the beginning of this post?) is easier,
cleaner, more flexible, and more secure.
Oh and to make the things even funnier you may take a look at this blog post: http://bitquabit.com/post/zombie-operating-systems-and-aspnet-mvc/
After reading those did you start using query strings? I hope you did.
you need to replace
new { controller = "ScanSummary", action = "Get" }
with
new { controller = "ScanSummary", action = "Get", domain = UrlParameter.Optional }
My Question Is This
What configuration step have I missed to make Mvc Surface Controllers work in Umbraco?
My theory is that since there is a folder in the default Umbraco install called /umbraco/ which is used to connect to the CMS that the physical path is interfiering with the route /umbraco/surface/{Controller}/{Action} thus resulting in the ASP.NET YSOD (and an IIS 404
when I try to access a controller on that route that isn't defined.)
Background Information
I have added this class to my App_Code folder in a freshly downloaded copy of Umbraco 6.1.6:
public class MembersController : SurfaceController
{
public ActionResult Index()
{
return Content("Hello, Member!");
}
}
When I navigate to what I think should be the route for my Index() method, I get a YSOD that says the resource could not be found:
the code is not executed and the above error is displayed; however, if I change the Uri to garbage I get an IIS 404 error:
I started getting this in an existing site, thinking my site was screwed up I tried it in a new copy of Umbraco 6.1.6 and got the exact same results.
For the record, I have also tried MembersSurfaceController and its associated Uri, which has the exact same result as above. YSOD when I hit the valid route, and IIS 404 when I don't.
I have changed my umbracoSettings.config to MVC in the /config/ directory as well.
update
I'm using the out-of-the-box web.config file, which has this:
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true">
<remove name="UrlRewriteModule" />
<add name="UrlRewriteModule" type="UrlRewritingNet.Web.UrlRewriteModule, UrlRewritingNet.UrlRewriter" />
.
..
...
On my default Umbraco site I don't have any rewrite rules defined; but on my actual site I have several rewrite rules in place. I'm thinking that's not causing it since I'm seeing the same behavior on both sites though...
I have tried removing UrlRewrite completely I get the same results.
The following approach works for me in Umbraco 7.1, and I expect it to work in 6.1 as well:
Create folder called 'Controllers' within your App_Code folder, and put your surface controllers in there (so that they will be within the 'Controllers' namespace).
E.g. I have the following controller in the App_Code\Controllers folder (and hence, within the 'Controllers' namespace):
namespace Controllers
{
public class ServiceCentersController : SurfaceController
{
public ActionResult GetServiceCenters(string country = "", string region = "", string city = "")
{
...
}
}
}
My site runs on localhost, so I can invoke the GetServiceCenters action by navigating to:
http://localhost/umbraco/Surface/ServiceCenters/GetServiceCenters?country=aa®ion=bb&city=cc
You need a namespace for your controller - the code posted above doesn't have any namespace:
public class MembersController : SurfaceController
{
public ActionResult Index()
{
return Content("Hello, Member!");
}
}
That is why making a namespace of Controllers works ... but you could make this any logically named namespace you want.
Well, I know it's IIS which is supposed to invoke it. Anyway; I have a Sharepoint solution which is supposed to return a special string when files with particular extensions are clicked on document libraries.
In the corresponding web.config file I have following to run this HTTP Handler:
<system.webServer>
<handlers>
...
<add name="MyFileHandler" path="*.bar" verb="*" type="Foo.Example.MyHandler, Foo.Example, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3b53a24010893ac2" resourceType="File" />
...
</handlers>
</system.webServer>
And the HttpHandler class is something like this:
namespace Foo.Example
{
public class MyHandler : IHttpHandler
{
public MyHandler(){} //For breakpoint
public void ProcessRequest(HttpContext context)
{
//Do stuff and write to response.
}
public bool IsReusable
{
get { return false; }
}
}
}
When I try to open a file with '.bar' extension on Sharepoint, it returns 404. What I do in ProcessRequest is not relevant because when I debug the handler, I can see that the handler's constructor is invoked but not the 'ProcessRequest'. Besides the debugger I have also put debug lines(File.AppendAll), again only the constructor gets invoked according to the debug output.
IIS 7.5.7600
Sharepoint 2010 Foundation
Turns out
resourceType="File"
on handler tag in web.config was the problem. Either remove it or set it as "Unspecified".
That is already mentioned here which, unfortunately, I failed to spot before.
The only thing I can think of is to try moving your handler to be really the first one.
Otherwise it could be better to actually integrate with SharePoint instead of trying to override its behavior. In this case you probably should post separate question for what you want to achieve.