Registering PATCH HTTP verb in IIS 7/7.5 - asp.net-mvc-3

I want to implement the recently approved PATCH HTTP verb in a RESTful service implemented with ASP MVC 3. I have added the following settings in the web.config file.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="PATCHVerbHandler" path="*" verb="PATCH" modules="ProtocolSupportModule" requireAccess="None" />
</handlers>
<security>
<requestFiltering>
<verbs>
<add verb="PATCH" allowed="true" />
</verbs>
</requestFiltering>
</security>
</system.webServer>
</configuration>
The action method is decorated with the AcceptVerbs("PATCH") attribute.
The service works properly with the PATCH verb. The URL gets routed to the right action method and returns the proper data.
The strange issue is if I using a different URL that does not match any routes using the PATCH verb, IIS returns "200 OK" instead of "404 Not Found". All the standard verbs (GET, PUT, DELETE, POST, HEAD, OPTIONS) do not have this problem.
Do I need to register additional handlers for the PATCH verb or is it a routing issue? Any help is appreciated.

You don't actually need a custom handler to process HTTP requests made with the PATCH verb; instead, you may want to keep decorating your actions with the AcceptVerbs("PATCH") attribute while checking that the ASP.NET ISAPI is configured to handle any verb (it is the default), including PATCH.
If you have to handle this kind of requests using a custom module, by the way, please keep in mind that it is the responsibility of the handler itself to set the status code for each request (including the ones it should handle, according to the mapping, but it can't for whatever reason) and maybe it is not setting the correct value upon finishing.

Related

Laravel Azure App Service Delete Method Not Allowed

Hosting a laravel app in Azure's App Service and every time the web application makes DELETE requests, it throws up 405 Method Not Allowed and returns the message below:
The page you are looking for cannot be displayed because an invalid method (HTTP verb) is being used.
I've exhausted all options I could find in the internet and tried all stuff mentioned. Hope someone could help.
If your application uses .NET WebAPI, you may get a 405 Method Not Allowed error when you issue a PUT or DELETE request.
This error is caused because the WebDAV module intercepted the request
In your web.config, try to insert this code
<system.webServer>
<modules>
<remove name="WebDAVModule" />
</modules>
<handlers>
<remove name="WebDAV" />
</handlers>
</system.webServer>
And this issue duplicate of this question

How to allow a DELETE method with IIS Express and Web API?

I am trying to send a delete request to my Web API service via Fiddler and am getting back a 405 "Method not allowed" error.
I have read extensively about removing the "WebDAV" module in web.config and similar suggestions (WebDAV is not enabled in my applicationhost.config anyway), but nothing I have tried has worked.
My service is currently running on IIS Express 10 (launching from Visual Studio). I do have this in my web.config file:
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0"/>
I would have thought the verb="*" piece would have allowed DELETE, but it does not seem to work.
One other note - when I inspect the response in Fiddler, under the Security heading it says: Allow: GET, POST.
I am not sure where that "Allow" parameter is being set (I am new to Web API).
Any help would be greatly appreciated. Please let me know what other information you need from me and I will add it.
Thank you!
Just reproduced this by creating a new webapi project [targeting .net framework 4.7.1]
Through Fiddler, I can hit the DELETE endpoint without any changes to web.config.
Please make sure to use correct endpoint including the id parameter.
e.g http:localhost:xxxx/api/values/id // please include the id and xxxx is port number.
If http:localhost:xxxx/api/values is used without id , I get the same result 405 Method Not Allowed
Hope this helps.
You can modify the IIS Express applicationHost.config in the %userprofile%\documents\IISExpress\config folder.  To enable PUT and DELETE for extensionless Urls scroll down to the bottom of the IIS Express applicationHost.config file and look for a handler entry that starts with: <add name="ExtensionlessUrl-Integrated-4.0".... In the "verb" attribute add PUT and DELETE so the "verb" attribute looks like:  verb="GET,HEAD,POST,DEBUG,PUT,DELETE"
Update your web config like this
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<modules runAllManagedModulesForAllRequests="true">
<remove name="WebDAVModule"/> <!-- ADD THIS -->
</modules>

OWIN Middleware: find if the request has a matched route

We would like to write a piece of OWIN middleware that looks at the current request and see if it matches any mapped routes (we are using web.api, so we register routes with the httpRouteCollection.MapHttpRoute method.
If the current request does not match any known configured routes we would like to reject it with a custom 404 message.
Is it possible to determine from the OWIN context whether the current request matches one of the defined routes?
The short answer is, no, you cannot. OWIN middleware does not designed to do that. It is independent of the application.
If you want a custom 404 error page, you can add a setting in the web.config file to do this for you:
<configuration>
<system.webServer>
<httpErrors>
<error statusCode="404" path="/somedir/oops404.htm" responseMode="ExecuteURL" />
</httpErrors>
</system.webServer>
</configuration>
Hope that helps.

The 'Access-Control-Allow-Origin' header contains multiple values

I'm using AngularJS $http on the client side to access an endpoint of a ASP.NET Web API application on the server side. As the client is hosted on a different domain as the server, I need CORS. It works for $http.post(url, data). But as soon as I authenticate the user and make a request via $http.get(url), I get the message
The 'Access-Control-Allow-Origin' header contains multiple values 'http://127.0.0.1:9000, http://127.0.0.1:9000', but only one is allowed. Origin 'http://127.0.0.1:9000' is therefore not allowed access.
Fiddler shows me that there are indeed two header entries in the get request after a successful options request. What and where am I doing something wrong?
Update
When I use jQuery $.get instead of $http.get, the same error message appears. So this seems no issue with AngularJS. But where is it wrong?
We ran into this problem because we had set up CORS according to best practice (e.g. http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api) AND ALSO had a custom header <add name="Access-Control-Allow-Origin" value="*"/> in web.config.
Remove the web.config entry, and all is well.
Contrary to #mww's answer, we still have EnableCors() in the WebApiConfig.cs AND an EnableCorsAttribute on the controller. When we took out one or the other, we ran into other issues.
I added
config.EnableCors(new EnableCorsAttribute(Properties.Settings.Default.Cors, "", ""))
as well as
app.UseCors(CorsOptions.AllowAll);
on the server. This results in two header entries. Just use the latter one and it works.
I'm using Cors 5.1.0.0, after much headache, I discovered the issue to be duplicated
Access-Control-Allow-Origin & Access-Control-Allow-Header headers from the server
Removed config.EnableCors() from the WebApiConfig.cs file and just set the [EnableCors("*","*","*")] attribute on the Controller class
Check this article for more detail.
Add to Register WebApiConfig
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
Or web.config
<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" />
<add name="Access-Control-Allow-Credentials" value="true" />
</customHeaders>
</httpProtocol>
BUT NOT BOTH
Apache Server:
I spend the same, but it was because I had no quotation marks (") the asterisk in my file that provided access to the server, eg '.htaccess.':
Header add Access-Control-Allow-Origin: *
Header add Access-Control-Allow-Origin "*"
You may also have a file '.htaccess' in a folder with another '.htaccess' out, eg
/
- .htaccess
- public_html / .htaccess (problem here)
In your case instead of '*' asterisk would be the ip (http://127.0.0.1:9000) server that you give permission to serve data.
ASP.NET:
Check that there is no 'Access-Control-Allow-Origin' duplicate in your code.
Developer Tools:
With Chrome you can verify your request headers. Press the F12 key and go to the 'Network' tab, now run the AJAX request and will appear on the list, click and give all the information is there.
I too had both OWIN as well as my WebAPI that both apparently needed CORS enabled separately which in turn created the 'Access-Control-Allow-Origin' header contains multiple values error.
I ended up removing ALL code that enabled CORS and then added the following to the system.webServer node of my Web.Config:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="https://stethio.azurewebsites.net" />
<add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS, PUT, DELETE" />
<add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept, Authorization" />
</customHeaders>
</httpProtocol>
Doing this satisfied CORS requirements for OWIN (allowing log in) and for WebAPI (allowing API calls), but it created a new problem: an OPTIONS method could not be found during preflight for my API calls. The fix for that was simple--I just needed to remove the following from the handlers node my Web.Config:
<remove name="OPTIONSVerbHandler" />
Hope this helps someone.
Actually you cannot set multiple headers Access-Control-Allow-Origin (or at least it won't work in all browsers). Instead you can conditionally set an environment variable and then use it in Header directive:
SetEnvIf Origin "^(https?://localhost|https://[a-z]+\.my\.base\.domain)$" ORIGIN_SUB_DOMAIN=$1
Header set Access-Control-Allow-Origin: "%{ORIGIN_SUB_DOMAIN}e" env=ORIGIN_SUB_DOMAIN
So in this example the response header will be added only if a request header Origin matches RegExp: ^(https?://localhost|https://[a-z]+\.my\.base\.domain)$ (it basically means localhost over HTTP or HTTPS and *.my.base.domain over HTTPS).
Remember to enable setenvif module.
Docs:
http://httpd.apache.org/docs/2.2/mod/mod_setenvif.html#setenvif
http://httpd.apache.org/docs/2.2/mod/mod_headers.html#header
BTW. The }e in %{ORIGIN_SUB_DOMAIN}e is not a typo. It's how you use environment variable in Header directive.
This happens when you have Cors option configured at multiple locations. In my case I had it at the controller level as well as in the Startup.Auth.cs/ConfigureAuth.
My understanding is if you want it application wide then just configure it under Startup.Auth.cs/ConfigureAuth like this...You will need reference to Microsoft.Owin.Cors
public void ConfigureAuth(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
If you rather keep it at the controller level then you may just insert at the Controller level.
[EnableCors("http://localhost:24589", "*", "*")]
public class ProductsController : ApiController
{
ProductRepository _prodRepo;
if you are in IIS you need to activate CORS in web.config, then you don't need to enable in App_Start/WebApiConfig.cs Register method
My solution was, commented the lines here:
// Enable CORS
//EnableCorsAttribute cors = new EnableCorsAttribute("*", "*", "*");
//config.EnableCors(cors);
and write in the web.config:
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
just had this problem with a nodejs server.
here is how i fixed it.
i run my node server through a nginx proxy and i set nginx and node to both allow cross domain requests and it didnt like that so i removed it from nginx and left it in node and all was well.
This can also happen of course if you've actually set your Access-Control-Allow-Origin header to have multiple values - For example, a comma separated list of values, which is kind of supported in the RFC but isn't actually supported by most major browsers. Note that the RFC talks about how to allow more than one domain without using '*' as well.
For example, you can get that error in Chrome by using a header like so:
Access-Control-Allow-Origin: http://test.mysite.com, http://test2.mysite.com
This was in Chrome Version 64.0.3282.186 (Official Build) (64-bit)
Note that if you're considering this because of a CDN, and you use Akamai, you may want to note that Akamai wont cache on the server if you use Vary:Origin, the way many suggest to solve this problem.
You'll probably have to change how your cache key is built, using a "Cache ID Modification" response behavior. More details on this issue in this related StackOverflow question
So stupid and simple:
This problem occurred for me when having two time Header always set Access-Control-Allow-Origin * inside my Apache config file. Once withing the VirtualHost tags and once inside a Limit tag:
<VirtualHost localhost:80>
...
Header set Access-Control-Allow-Origin: *
...
<Limit OPTIONS>
...
Header set Access-Control-Allow-Origin: *
...
</Limit>
</VirtualHost>
Removing one entry resolved the issue.
I guess in the original post it would have been two times:
Header set Access-Control-Allow-Origin: "http://127.0.0.1:9000"
The 'Access-Control-Allow-Origin' header contains multiple values
when i received this error i spent tons of hours searching solution for this but nothing works, finally i found solution to this problem which is very simple.
when ''Access-Control-Allow-Origin' header added more than one time to your response this error occur, check your apache.conf or httpd.conf (Apache server), server side script, and remove unwanted entry header from these files.
For only Spring Boot :
This occurs because u might be using the
#CrossOrigin(origins = "http://localhost:4200")
twice in the application or else, you might be using :
#CrossOrigin(origins = "*")
The browsers do not support it.Check here for more details on it
please specify the Url even in the security config :
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
configuration.setAllowedMethods(Arrays.asList("GET","POST","PUT","DELETE"));
configuration.setAllowedHeaders(Arrays.asList("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
Then Add this in the Http security configure :
.and().cors().configurationSource(corsConfigurationSource());
I have faced the same issue. The reason in my case was that I had the wrong NGINX configuration for reverse proxy (which I used for the Docker container with node.js app).
add_header 'Access-Control-Allow-Origin' '*'
So for those who are using VMs and docker, there are more places where issues are possible to occur.
I have faced the same issue and this is what I did to resolve it:
In the WebApi service, inside Global.asax I have written the following code:
Sub Application_BeginRequest()
Dim currentRequest = HttpContext.Current.Request
Dim currentResponse = HttpContext.Current.Response
Dim currentOriginValue As String = String.Empty
Dim currentHostValue As String = String.Empty
Dim currentRequestOrigin = currentRequest.Headers("Origin")
Dim currentRequestHost = currentRequest.Headers("Host")
Dim currentRequestHeaders = currentRequest.Headers("Access-Control-Request-Headers")
Dim currentRequestMethod = currentRequest.Headers("Access-Control-Request-Method")
If currentRequestOrigin IsNot Nothing Then
currentOriginValue = currentRequestOrigin
End If
If currentRequest.Path.ToLower().IndexOf("token") > -1 Or Request.HttpMethod = "OPTIONS" Then
currentResponse.Headers.Remove("Access-Control-Allow-Origin")
currentResponse.AppendHeader("Access-Control-Allow-Origin", "*")
End If
For Each key In Request.Headers.AllKeys
If key = "Origin" AndAlso Request.HttpMethod = "OPTIONS" Then
currentResponse.AppendHeader("Access-Control-Allow-Credentials", "true")
currentResponse.AppendHeader("Access-Control-Allow-Methods", currentRequestMethod)
currentResponse.AppendHeader("Access-Control-Allow-Headers", If(currentRequestHeaders, "GET,POST,PUT,DELETE,OPTIONS"))
currentResponse.StatusCode = 200
currentResponse.End()
End If
Next
End Sub
Here this code only allows pre-flight and token request to add "Access-Control-Allow-Origin" in the response otherwise I am not adding it.
Here is my blog about the implementation: https://ibhowmick.wordpress.com/2018/09/21/cross-domain-token-based-authentication-with-web-api2-and-jquery-angular-5-angular-6/
for those who are using IIS with php,
on IIS it server side update web.config file it root directory (wwwroot) and add this
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<directoryBrowse enabled="true" />
<httpProtocol>
<customHeaders>
<add name="Control-Allow-Origin" value="*"/>
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
after that restart IIS server,
type IISReset in RUN and enter
Here's another instance similar to the examples above that you may only have one config file define where CORS is: There were two web.config files on the IIS server on the path in different directories, and one of them was hidden in the virtual directory.
To solve it I deleted the root level config file since the path was using the config file in the virtual directory.
Have to choose one or the other.
URL called: 'https://example.com/foo/bar'
^ ^
CORS config file in root virtual directory with another CORS config file
deleted this config other sites using this
I had this issue because I add in the my webconfig project and also webconfig endpoint this config:
<add name="Control-Allow-Origin" value="*"/>.
When I remove <add name="Control-Allow-Origin" value="*"/> from webconfig endpoint the problem was solved.

Routing requests that end in ".cshtml" to a controller

(This is cross-posted to the ASP.NET forms)
I'm working on the WebGit .NET project, and we are close to a "1.0" release. However, I'm having trouble getting my "Browse" controller (which pulls files out of the repository) to serve-up ".cshtml" files.
I originally had trouble with ".config" and ".cs" files as well, but I fixed that with this in the web.config:
<location path="browse">
<system.webServer>
<security>
<requestFiltering>
<fileExtensions allowUnlisted="true">
<clear />
</fileExtensions>
<hiddenSegments>
<clear />
</hiddenSegments>
</requestFiltering>
</security>
</system.webServer>
</location>
The routing that should be handling this request (that is successfully routing everything else) is:
routes.MapRoute(
"View Blob",
"browse/{repo}/blob/{object}/{*path}",
new { controller = "Browse", action = "ViewBlob", path = UrlParameter.Optional });
Now, whenever I try to access a URL that ends in ".cshtml", it gives a 404, even though my request should have been handled by the "Browse" controller. The files I'm serving-up do not exist on disk, but are instead pulled from a git repository as blobs. Every other file extension that I have tried works just fine.
How can I fix this behavior?
EDIT: I have tried disabling WebPages like so:
<appSettings>
<add key="webpages:Enabled" value="false" />
</appSettings>
But that appears to have no effect.
As a quick workaround, you can put a temporary browse.cshtml file at your application root and put this inside your web.config,
add key="webpages:Enabled" value="false"
This is a known bug in ASP.NET WebPages, which gets implicitly loaded when you are using MVC 3. I don't think there is a straightforward way of disabling this behavior. The only workaround is to use a different extension (specifically, one that is not listed via WebPageHttpHandler.GetRegisteredExtensions())
This will be fixed in MVC 4, however. Sorry for the inconvenience.

Resources