HTTP Error 405.0 – Method Not Allowed in IIS Express

iisiis-7iis-7.5iis-expressvisual-studio-2013

When issuing a perfectly cromulent verb to a local IIS Express web-site under Visual Studio 2013:

CROMULENT http://localhost:7579/Handler.ashx HTTP/1.1
Host: localhost:7579

the server responds with the error:

HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD, OPTIONS, TRACE

That is a request to a "generic handler" (i.e. .ashx). If if i try again to a static resource:

SCHWIFTY http://localhost:7579/Default.htm HTTP/1.1
Host: localhost:7579

the server responds with the error:

HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD, OPTIONS, TRACE

This is all by way to trying to use HTTP verbs:

DELETE http://localhost:7579/Handler.ashx HTTP/1.1
Host: localhost:7579

HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD, OPTIONS, TRACE

PUThttp://localhost:7579/Handler.ashx HTTP/1.1
Host: localhost:7579

HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD, OPTIONS, TRACE

This question has been asked to death, sometimes by me. But nobody has ever come up with a solution.

</Question>

Microsoft's Bug

The problem, fundamentally, is that Microsoft ships IIS and IISExpress broken by default. Rather than handling HTTP verbs, as a web-server is required to do, they don't handle verbs.

This can most easily be seen when managing full IIS running on Windows Server. Pick any of the built-in handlers (e.g. the cshtml handler), and you can see that someone thought it would be hilarious if it only worked with GET, HEAD, POST, and DEBUG verbs:

enter image description here

rather than correctly implementing support for HTTP in an HTTP server.

The question becomes:

  • why exactly doesn't it work
  • how exactly to fix it
  • how to fix it in IIS Express (without any management tools)
  • why it continues to be shipped, year after year, broken

Question 1. Why doesn't it work?

The first question is why doesn't it work. Let's look at an IIS server where we've removed every handler except the basic Static file handler:

enter image description here

The handler is configured to all all verbs:

enter image description here

The only handler left is set to allow any verb. Yet if we issue a request to the web server we get the error:

DELETE http://scratch.avatopia.com/ HTTP/1.1
Host: scratch.avatopia.com

HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD, OPTIONS, TRACE
Server: Microsoft-IIS/7.5

Why is this happening?

Why didn't it work? Where is the configuration option that says:

  • GET
  • HEAD
  • OPTIONS
  • TRACE

because the server itself is saying those are the only supported verbs.

Yet if we change it to a GET it works fine:

GET http://scratch.avatopia.com/ HTTP/1.1
User-Agent: Fiddler
Host: scratch.avatopia.com

HTTP/1.1 200 OK
Content-Type: text/html

Question 2. How to fix it?

The common wisdom is to remove WebDAV. Nobody knows what WebDAV is, how it could be a problem, why it is a problem, or why it exists if it only causes problems. WebDAV can be removed as a handler from the IIS administration user interface:

enter image description here

which is identical to adding a remove entry from the handlers section in web.config (the UI itself adds the entry to web.config for you):

<system.webServer>
    <handlers>
        <remove name="WebDAV" />
    </handlers>
</system.webServer>

Except this doesn't work. So how do we fix it?

Starting with IIS it seems that WebDAV has become even more of a virus. Rather than simply disabling it as a handler, you have to completely install or remove it as a module:

<system.webServer>
  <modules>
    <remove name="WebDAVModule" />
  </modules>
  <handlers>
    <remove name="WebDAV" />
  </handlers>
</system.webServer>

That sounds like a reason idea, except in my test case, on IIS 7.5, WebDAV is both not installed, and removed as a module:

HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD, OPTIONS, TRACE
Server: Microsoft-IIS/7.5
X-Powered-By: ASP.NET
Date: Tue, 10 May 2016 19:19:42 GMT
Content-Length: 0

So, if we can figure out how to solve the problem, we can answer question number two.

Question 3. How to fix it in IIS Express

Starting with Visual Studio 20131, Visual Studio no longer uses a mini web-server called Cassini. It uses a portable install of IIS Express itself (i.e. IIS Express Windows feature doesn't need to be installed).

Most of the above fix (attempts) (fail) in IIS. But nobody has dealt with them in IIS Express of Visual Studio 2013 (which is how this question is different from any others).

Question 4. Why does this keep happening?

It's been over 15 years, and this still keeps happening. There must be a good reason why IIS does not function as a web-server. But what is it? I've not been able to find any knowledge base article, or blog post, explaining why the IIS team refuses to function correctly.

Bonus Reading

Research Effort

Best Answer

I seem to pick up on a bit of frustration in the question, so the actual question is a bit unclear. What specifically is it that you are trying, but failing, to do? What do you expect of the answer?

Anyway, based on this comment in the question:

This is all by way to trying to use HTTP verbs:

and the corresponding samples involving a generic handler, I'll take a stab at showing what is needed to make it possible to PUT and DELETE a generic handler.

In order to allow PUT and DELETE on a generic handler, you must allow it in the web.config of the application. To do that you should register a handler for *.ashx as follows:

<system.webServer>
    <handlers>
        <add name="SimpleHandlerFactory-Integrated-WithPutDelete"
            path="*.ashx"
            verb="GET,HEAD,POST,DEBUG,PUT,DELETE"
            type="System.Web.UI.SimpleHandlerFactory"
            resourceType="Unspecified"
            requireAccess="Script"
            preCondition="integratedMode" />
    </handlers>
</system.webServer>

Depending on how you originally set up the web site/application, there may or may not be a handler registered for type="System.Web.UI.SimpleHandlerFactory" in your web.config file. If there is one, you should be able to just modify that entry and add the verbs you want to allow.

You'll note that this entry has the preCondition="integratedMode". This should, I believe, work when debugging in Visual Studio using IIS Express. In a real IIS deployment, the handler registration may need to be modified to match the application pool that will run the application. For an application running in classic mode (not integrated), it would look something like this (not tested so may be wrong):

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

The exact details would depend on the framework version an bit-ness of the application pool.

If you are debugging in Visual Studio using IIS Express, you should have a look at the applicationhost.config which sets up a lot of the defaults regarding IIS Express. It is located in:

My Documents\IISExpress\config

The untested handler registration above for a classic pipeline application pool is a slight modification of a handler registration in that file. There are in my environment 6 separate entries for *.ashx, with varying preconditions, in that file.

It might be a good idea to explicitly remove all of these in your web.config if you want to have your own registration which allows PUT and DELETE. Not all of them would actually be active/registered at the same time since the preconditions are (I suppose) mutually exclusive, but at least for me it works to just remove them all, one after the other. In my environment the section with the removes looks like this:

<remove name="SimpleHandlerFactory-ISAPI-4.0_64bit"/>
<remove name="SimpleHandlerFactory-ISAPI-4.0_32bit"/>
<remove name="SimpleHandlerFactory-Integrated-4.0"/>
<remove name="SimpleHandlerFactory-Integrated"/>
<remove name="SimpleHandlerFactory-ISAPI-2.0"/>
<remove name="SimpleHandlerFactory-ISAPI-2.0-64"/>

Hope this shines at least a bit of light into dark places!