I have an interesting case I cannot explain, and I need help figuring out what my problem is on IIS7:
Given:
See the following controller:
public class ServiceController : Controller
{
public ActionResult Test()
{
return Content("Test");
}
[HttpPost]
public ActionResult Test2()
{
return Content("Test2");
}
}
Additionally, in Global.asax there is this code:
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 404)
{
ExecuteIndexPage();
}
}
protected void Application_Error(object sender, EventArgs e)
{
var error = Server.GetLastError();
ExceptionLogger.Log(error);
ExecuteIndexPage();
}
So, whenever there is a server error, this is logged. In this case and in the case of a normal 404, the start page is returned. This works (almost) fine. More to that later.
This setup gives very different behaviours on IIS7 (Windows Server 2008, production environment) and IIS7.5 (Win7 Pro, Development environment and Windows Server 2008 R2, also production environment).
Given the following configuration in IIS (both versions):
In IIS 7.5 the behaviour is:
In IIS 7 the behaviour instead is:
So, IIS 7 and IIS 7.5 work great when using GET requests, except when there is no route. When there is no route, IIS 7.5 executes the Global.asax end request with status code 404 and delivers the index page. IIS 7 does NOT execute Global.asax end request. Why? I could (and currently do) work around this issue by registering a {*catchall} route, so that a matching route exists.
As soon as I am trying to use HTTP POST, IIS 7 does work even less than I would expect.
When POSTing the request, IIS 7 does not execute any code in my application whatsoever, and directly returns an IIS 404 page.
So my question is: Why does IIS 7 refuses so hard to handle POST requests in my MVC 4 application, and what can I do to have it also handle post request?
We figured it out - finally.
The default configuration inserts this in the web.config:
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true" />
<handlers>
<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" />
</handlers>
</system.webServer>
The problem is the "*." path, which would cover /test.aspx but not simply /test.
If you change this to "*", then all requests will be handled by the ExtensionlessUrlHandler, including those to static files which will not be served anymore.
So the solution is: Remove the POST verb from the handler entries and add new entries for the ExtensionlessUrlHandler with the path set to "*" and only for POST requests:
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,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,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,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit_post" path="*" verb="POST" 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_post" path="*" verb="POST" 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_post" path="*" verb="POST" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
Ideally remove the ones you don't need (x86 and x64 in classic vs. integrated pipeline).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With