asp.net-mvcvisual-studioasp.net-mvc-5msbuildwebdeploy

How to make sure all *.cshtml files are set to be "Content" for Build Action


A few times when I copy-paste *.cshtml files, Visual Studio for some reason sets the Build Action on these files to be "None": Comments.cshtml is set to be "None" on Build Action

This is impossible to detect when you work locally, because the files are present. But when you deploy through WebDeploy, files marked as "None" on Build Action are not packaged. As a result I get non-working application on the server.

Is there a way to automatically detect such occurrences and prevent?


Solution

  • You could extend the .csproj with a small snippet that will generate a warning when an item in the "None" group has the extension .cshtml. The snippet would be:

    <Target Name="EnsureContentOnViews" BeforeTargets="BeforeBuild">
      <ItemGroup>
        <Filtered Include="@(None)" Condition="'%(Extension)' == '.cshtml'" />
      </ItemGroup>
      <Warning 
        Condition="'@(Filtered)'!=''"
        Code="CSHTML" 
        File="$(MSBuildProjectDirectory)\%(Filtered.Identity)" 
        Text="View is not set to [BuildAction:Content]"
      />
    </Target>
    

    If you see other build actions (like EmbeddedResource), you can add them to the Filtered item definition.

    If you want more advanced detection you need to actually parse the project files for any item that fits this Xpath //ItemGroup/*[not(self::Content)]/@Include

    <Target Name="EnsureContentOnViewsXML" BeforeTargets="BeforeBuild">
      <XmlPeek XmlInputPath="$(MSBuildProjectFile)" Namespaces="&lt;Namespace Prefix='msb' Uri='schemas.microsoft.com/developer/msbuild/2003'/&gt;"; Query="/msb:Project/msb:ItemGroup/*[not(self::msb:EmbeddedResource)]/@Include">
        <Output TaskParameter="Result" ItemName="AllItems" />
      </XmlPeek>
    
      <!-- MsBuild uses XPath 1.0 which doesn't have the 'ends-with' or 'matches' function. -->
      <ItemGroup>
        <Filtered Include="@(AllItems)" Condition="'%(Extension)' == '.cshtml'" />
      </ItemGroup>
    
      <Warning 
        Code="CSHTML" 
        File="$(MSBuildProjectDirectory)\%(Filtered.Identity)" 
        Text="View is not set to [BuildAction:Content]"
        Condition="'@(Filtered)'!=''"
      />
    </Target>
    

    Instead of <Warning ...> you can also use <Error ...>

    You'll need to manually put one of these snippets in your project file:

    enter image description here