Make sure all *.cshtml files are set to be “Content” for Build Action

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

Leave a Comment