I have been working on a small Website built with Visual Studio 2013, .Net 4.5, Entity Framework (code-first), and MVC 5. I started out with the MVC template for responsive sites that includes Bootstrap. Everything went smoothly until I deployed the site to our QA server.
This box runs Windows Server 2008 x64 (no, not R2). I naively published my app to a local folder and copied everything to the server folder that I created for the new website. After I updated the connection string in the web.config and started the site, I got the ominous
HTTP Error 403.14 - Forbidden The Web server is configured to not list the contents of this directory.
when I tried to hit the home page. Little did I know that it would take me the next 6 hours to figure out what was going on. Because I had to once again sift through so much misinformation on the web about this issue, I am going to write up what I found.
Common things to check when a website does not run properly are
- The app pool configuration
- pipeline mode
- target .Net framework (4.0.30319 is the latest, and 4.5.1 is installed)
- Folder security (allow access for the app pool user)
- Website security (anonymous access is needed for my site)
- Re-register ASP.Net by running aspnet_regiis ad nauseam
None of these things applied, though, because I had done a thorough job installing .Net 4.5.1 and configuring my site.
Because IIS seemed to be set up and configured correctly for my website, I looked at the way I deployed. Maybe something was missing?
I installed the Web Platform Installer on our server and added the Web Deploy plugin (3.5). This is required if you want to either use the one-click deployment from Visual Studio or use the Web Deployment Package script that Visual Studio generates. I removed my website from the server, recreated it from scratch, and tried both deployment methods in Visual Studio with the same results.
From the error message it appears that MVC is not working properly. IIS is looking for a default page to load, does not find one in the root of an MVC site, and can’t show the folder content because folder browsing is disabled. But why? Clearly this has to do with the way requests are routed to the correct module in IIS, and somewhere this process is broken.
There are dozens of questions on Stackoverflow related to this issue with answers all over the map, some trivial, some complex. I came back to the same recommendation, though, because nothing else seemed to apply: adding these lines to the web.config:
There are valid concerns about implementing such a drastic measure, though, for example by Rick Strahl or by this chap. I tried to add this manually to my web.config, but only got an error. My IIS did not understand the
<system.webServer> section, even though I followed the documentation closely.
None of the hot fixes that were referenced in these posts worked for me (for example this one or this one), presumably because I am on Server 2008 and not R2, and when I tried to install, I would only get the message that the hotfix does not apply to my server. And by the way, the server is current with patches, so any hotfixes would have been applied in the past anyway.
The bin folder contained all the necessary assemblies for MVC (MVC 5 does not need to be deployed as a prerequisite because it is part of the web site deployment package).
And yet, for some reason, MVC did not rewrite the URL to invoke the correct handlers for my site. So, after more poking around in various Stackoverflow articles and blog posts I had a break-through when I finally came across this one on MSDN. It explains how to use the IIS Manager’s GUI to explicitly add the UrlRoutingModule to the web.config, even though it showed up as installed for my site:
After I unchecked the “Invoke only for requests to ASP.NET applications or managed handlers” checkbox the Entry Type changed to Local (see the screen shot above) and a corresponding section appeared in my web.config. IIS suddenly began to understand
<system.webServer> section (I still don’t know why), and the site started to render MVC views.
The section that was added, btw, is this one:
<remove name="UrlRoutingModule-4.0" />
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
I had seen this before at this point, but only now it made sense to me. What still does not make sense to me is why this was necessary and why
a. Visual Studio had not included this in the web.config
b. The routing module was not invoked without this setting.