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

倖福魔咒の 提交于 2019-12-20 09:47:18

问题


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

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.

Question: is there a way to automatically detect such occurrences and prevent?


回答1:


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:




回答2:


Thank you jessehouwing for geting me started! I liked your solution and voted for it. I had a little trouble with it and ended up with the following:

<Target Name="EnsureContentOnViews" BeforeTargets="BeforeBuild">
    <ItemGroup>
      <Filtered Include="@(None)" Condition="'%(Extension)' == '.cshtml'" />
    </ItemGroup>
    <Error Condition="'@(Filtered)'!=''" Code="CSHTML" File="%(Filtered.Filename)" Text="Not set to [BuildAction:Content]: Identity: %(Filtered.Identity)" />
</Target>

Right before my </Project> tag in the csproj file.




回答3:


Well, @jessehouwing 's certainly worked for me! So that fix stays nicely in my .csproj file :).... Only, I just double-checked and it looks as if that nice snippet disappeared somewhere in the last month due to a merge of another developer or something.. (true story)

NPM alternative

Anyway, I would like to mention the NPM module check-vs-includes I created for this. It is especially convenient for dev's that have Node installed (and if you don't then you probably should :) ).

I run the check manually before each deploy, instead of on every build. But it is less likely to disappear (unnoticed) from your .csproj file due to a merge.

The main advantage however of using this NPM package, is that besides checking for Build Action NONE it also checks for files that are NOT included in your project at all. Because that can also lead to (subtle but nasty) bugs when you use Visual Studio's Web Deploy. And missing includes are actually pretty likely if: 1) you have 1 non VS developers in your team, or 2) due to merges of the .csproj file (which often has merge issues).

Check the NPM page for instructions. But below a simple example, which assumes you use Node and Gulp:

Simple example

  1. Install the Node module

    npm i check-vs-includes

  2. Add a task to your gulpfile.js:

     var checkVSIncludes = require('check-vs-includes');

     ...

     gulp.task('checkVSIncludes', function() {
        checkVSIncludes(['/Views/**/*.cshtml', '/app/**/*.js']);
     });
  1. Run the check in your project folder (e.g. where your .csproj file is)

    gulp checkVSIncludes




回答4:


I suggest to implement a custom build task. Call it on prebuild in your msbuild/tfs script. Custom build task should just check .scproj file if there is an include file of cshtml with build action none. Of so just exit returning a non zero int value.



来源:https://stackoverflow.com/questions/27954267/make-sure-all-cshtml-files-are-set-to-be-content-for-build-action

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!