I have an existing ASP.NET Web API 2 project that was previously served under route prefix /api/ (example.com/api/Users), but now it needs to be moved directly under the root (example.com/Users).
The problem is that now some of the routes match physical directories in the project root, and IIS tries to serve those directories when making such conflicting request.
This is what the project structure looks like:
MyApi/
App_Start/
Controllers/
Models/
...
Permissions/
...
Global.asax
Global.asax.cs
...
Web.config
The routes are mapped using attribute routes: config.MapHttpAttributeRoutes();
And here's a simplified sample of a problematic controller:
namespace MyApi.Controllers
{
[RoutePrefix("Permissions")]
public class PermissionController
{
[Route("")]
[HttpGet]
[ResponseType(typeof(IEnumerable<Permission>))]
public IHttpActionResult Get()
{
return ...
When a request is made to example.com/Permissions, IIS first responds with a 301 redirect to example.com/Permissions/ (trailing slash) and then with:
IIS 10.0 Detailed Error
HTTP Error 403.14 - Forbidden
The Web server is configured to not list the contents of this directory.
Detailed Error Information:
Module DirectoryListingModule
Notification ExecuteRequestHandler
Handler StaticFile
Error Code 0x00000000
All other controllers without conflicting directory names work as expected.
I've tried both enabling and disabling runAllManagedModulesForAllRequests, I've tried adding and removing handlers like this:
<add name="ApiURIs-ISAPI-Integrated-4.0" path="*" type="System.Web.Handlers.TransferRequestHandler" verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" preCondition="integratedMode,runtimeVersionv4.0" />
And I've even tried removing the StaticFile handler, but nothing I've tried so far has worked.
This is the Web.config currectly. It is identical to what Visual Studio 2015 generates by default when creating a new empty Web API 2 project:
...
<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>
...
So can I prevent IIS from trying to serve physical files inside the project? The API should only serve dynamically generated content from the controllers.
After a lot of trial and error, I seem to have found the solution.
This flag makes the API prefer the controller instead of the directory:
System.Web.Routing.RouteTable.Routes.RouteExistingFiles = true;
Changes for Web.config:
runAllManagedModulesForAllRequests allows dots in the URL (/Users/firstname.lastmane)StaticFile handler will return 404 errors instead of 403 erros for physical directories which don't match any mapped routes.Content:
...
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<remove name="StaticFile" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
...
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