MVCBuildViews not working correctly

So I edited my csproj file on an MVC 3 RTM application to set the following property:

<MvcBuildViews>true</MvcBuildViews>

This should cause my views to be complied during build and force a build error if my view is broken. This is the only change I made, however, when I try to build the application, I get the following error:

It is an error to use a section registered as allowDefinition='MachineToApplication' beyond application level. This error can be caused by a virtual directory not being configured as an application in IIS.

The project compiles and runs successfully if I change back to false,

The following are the build tasks configured in the csproj file (these were never manually edited, they were added by Visual Studio 2010)

<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target> -->
<Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
  <AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
</Target>

Am I missing something here? How do I get MVC 3 / Visual Studio 2010 configured correctly to validate my views at build time?


Solution 1:

I had this problem a few days ago and I fixed it by deleting obj/Debug folder. Cleaning the project also works. I have no idea about the cause of the issue, though.

See Joe Cartano's answer for a more permanent solution.

Solution 2:

This problem occurs when there is web project output (templated web.config or temporary publish files) in the obj folder. The ASP.NET compiler used isn't smart enough to ignore stuff in the obj folder, so it throws errors instead.

Another fix is to nuke the publish output right before calling <AspNetCompiler>. Open your .csproj and change this:

<Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
  <AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
</Target>

to this:

<Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
  <ItemGroup>
    <ExtraWebConfigs Include="$(BaseIntermediateOutputPath)\**\web.config" />
    <ExtraPackageTmp Include="$([System.IO.Directory]::GetDirectories(&quot;$(BaseIntermediateOutputPath)&quot;, &quot;PackageTmp&quot;, System.IO.SearchOption.AllDirectories))" />
  </ItemGroup>
  <Delete Files="@(ExtraWebConfigs)" />
  <RemoveDir Directories="@(ExtraPackageTmp)" />
  <AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
</Target>

That will delete all web.configs under \obj, as well as all PackageTmp folders under \obj.

UPDATE:

Even better, based off https://stackoverflow.com/a/48582282/8037 you can exclude the obj folder entirely. Apparently the <AspNetCompiler /> task doesn't have an exclude parameter, but if you switch to calling the aspnet_compiler .exe directly, you can exclude obj like this:

<Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
    <Exec Command="$(MSBuildFrameworkToolsPath)aspnet_compiler.exe -v temp -p $(WebProjectOutputDir) -x $(BaseIntermediateOutputPath)"/>
</Target>