有没有一种方法可以自动将内容文件包含到asp.net项目文件中?


86

我经常在ASP.NET项目中添加很多内容文件(主要是图像和js)。我正在使用VS发布系统,并且在发布时,直到将新文件包含在项目中之后,才会发布新文件。我想自动包含指定目录中的所有文件。有没有一种方法可以指定哪些目录应自动包含在csproj文件或其他任何地方?



1
不正是我要找的
马尔科

在修改vs解决方案浏览器中的文件夹时,我更新了回答有关您问题的答案。
Filburt

Answers:


134

我知道老线程,但是我找到了一种方法,但我一直忘了它,而在上次寻找它的搜索中,我偶然发现了这个问题。我发现最好的方法是使用.csproj文件中的BeforeBuild目标。

<Target Name="BeforeBuild">
    <ItemGroup>
        <Content Include="**\*.less" />
    </ItemGroup>
</Target>

VS 2010不会涉及此部分,它可确保每次构建项目时文件都作为内容包含在内。


.less是什么意思?整个字符串是什么意思**\*.less
注册用户

3
.less文件是由Less CSS预处理程序解析的css文件。谷歌“少点”以获取更多信息。该表达式**\*.less表示在所有目录中包括所有* .less文件。用MSBUILD讲,**表示“所有目录都递归”
Chris

4
至少在VS 2012中,一旦您从项目中添加/删除文件并保存,不幸的是,该文件会扩展到完整列表。:(
克里斯·菲利普斯

3
仅在将BeforeBuild更改为AfterBuild之后,这才适合我的情况,我的构建启动了一个Powershell脚本来移动文件,然后我的azure Web部署尝试不会拾取这些文件,因为它们仅在构建成功之后才存在。看到“ BeforeBuild”使我意识到可能也有一个“ AterBuild”。希望这对其他人有帮助。
路加·赖斯

1
@John在下面查看我的答案以获取VS2015 +的修复程序。
杰西

54

您只需扩展您的网站.csproj文件即可。只需使用递归通配符添加内容根文件夹:

...
<ItemGroup>
    <!-- your normal project content -->
    <Content Include="Default.aspx" />

    <!-- your static content you like to publish -->
    <Content Include="Images\**\*.*" />
</ItemGroup>
...

这样做会使此文件夹以及下面的所有内容在解决方案浏览器中可见。

如果您尝试通过指定隐藏解决方案浏览器中的文件夹

<Content Include="Images\**.*.*">
    <Visible>false</Visible>
</Content>

它不会被发布。


更新资料

正如您已经发现的那样,一旦您触摸解决方案中的文件夹,通配符将被替换,因为VS项目并非旨在包含任意内容。

因此,您必须确保文件夹和其内容绝不会在VS内进行修改-添加或删除文件只能在文件系统上进行...这就是您想要的,因为我了解您的问题。

如果该文件夹可以在VS中隐藏,但我找不到隐藏它并发布的方法,将会更容易。

另一种不成功的方法是按CreateItem任务包含文件夹。这导致该文件夹的内容被发布到\ bin \ app.publish \ ...,并且无法说服将其与.csproj中的内容项一起发布,因此我没有在回答中给出它。


3
在我手动添加或删除文件之前,它一直有效。在该行之后,<Content Include =“ Images * *。 ” />从项目文件中消失。
Marko,2010年

2
@Marko是正确的。添加<Content Include="Images\**\*.*" />后有效。添加更多图像后,.csproj便会更改,并返回列出图像中的所有文件/ ...,<Content Include =“ Images * *。 ” />消失了。
拉维·拉姆

将此代码粘贴在单独的.proj文件中,然后从.csproj文件中的before build目标调用该代码。
NL-向Monica道歉

21

对于使用Chris的答案有问题的人,这是Visual Studio 2012及更高版本的解决方案:

<Target Name="ContentsBeforeBuild" AfterTargets="BeforeBuild">
  <ItemGroup>
    <Content Include="images\**" />
  </ItemGroup>
</Target>

克里斯(Chris)在回答中提到-即使您手动在目标目录中随意<Target>摆弄(添加/删除文件),Visual Studio也不会涉及到此部分。

请注意,您应该在其中包含文件的子目录(在上述情况下为images)。Visual Studio / MSBuild会将这些文件放在项目结构内的同一目录中。如果不使用子目录,则文件将放置在项目结构的根目录下。

有关通配符的快速说明:

  • **递归地表示所有内容(文件,子目录和其中的文件)
  • *.extext在顶层目录中包含所有带有扩展名的文件,但不包括子目录
    • 例如,*.ext可能是*.png*.js等。任何文件扩展名都可以使用
  • **\*.ext将包括ext顶级目录和所有子目录中所有带有扩展名的文件。
  • 请参阅“如何使用Nant / Ant命名模式”中的答案有关示例的更完整说明。

为了完成操作,请注意,使用<Target>和不使用它是有区别的。

通过这种<Target>方法,Visual Studio将不会在解决方案资源管理器中显示文件。

<Target Name="ContentsBeforeBuild" AfterTargets="BeforeBuild">
  <ItemGroup>
    <Content Include="images\**" />
  </ItemGroup>
</Target>

<Target>方法指示Visual Studio在解决方案资源管理器中显示文件。这样做的缺点是,对自动目录的任何操作都会导致Visual Studio覆盖通配符条目。还应注意,以下方法在VS中打开“解决方案/项目”后才会更新“解决方案资源管理器”。甚至解决方案资源管理器的“刷新”工具栏按钮也不会执行此操作。

<ItemGroup>
  <Content Include="images\**" />
</ItemGroup>

1
感谢您进行实验并指出使用<Target>与不使用之间的区别。也很好地解释了通配符的细节。
Kurt Hutchinson

@KurtHutchinson-没问题。=)
杰西

我相信此解决方案需要完善。当您指示目标在“ BeforeBuild”之后运行时,从理论上讲,这也可能在发布后发生。当前的解决方案可能是运气好的原因。
伊姆雷·普维尔(ImrePühvel)

@ImrePühvel您如何在活动开始之前发布图片BeforeBuild?MSBuild必须首先构建项目和二进制文件,然后才能考虑发布。
杰西

1
我并没有声称发布是在构建之前发生的,但是声明并不能保证在发布之前将项目添加到内容中。从代码示例:.. AfterTargets="BeforeBuild"。意思是,您的自定义目标必须在BeforeBuild之后执行,但是没有指定之后多少。但是,我的错误是,按当前的目标排序算法应该没问题:msdn.microsoft.com/en-us/library/ee216359.aspx
ImrePühvel18年

10

您可以使用框架的System.IO.Directory.GetFile(string)方法及其重载来递归包括所有文件。

  <ItemGroup>
    <Content Include="$([System.IO.Directory]::GetFiles('$(ProjectDir)Scripts\', '*.js', SearchOption.AllDirectories))" />
    <Content Include="$([System.IO.Directory]::GetFiles('$(ProjectDir)Images\', '*.png', SearchOption.AllDirectories))" />
  </ItemGroup>

这对我有很大帮助;我有多个目录,深几个级别,而且我想自动包含很多文件,这使所有这些内容变成一个。谢谢!
杰伊·奥特伯恩

2
我对此进行了更多的实验,结果发现它具有Include="**\*.ext"与通配符相同的局限性。
史蒂文·里肯斯

哇,项目文件包含运行powershell吗?那是沙盒吗?这是一个等待发生的漏洞。
Brain2000

不是PowerShell。MSBuild具有用于调用静态方法的自身语法。根据文档,这仅限于系统类。docs.microsoft.com/zh-cn/visualstudio/msbuild/… 尽管我敢肯定您可以使用任何参数使用<Exec> powershell ...
Steven Liekens

3

我已经写出了如何使用小型Powershell脚本创建包含内容的方法:

$folders = Get-ChildItem .\ -r -Directory
$filtered = $folders |Select-Object @{Name='FullName';Expression={$_.fullname.replace($pwd,'')}}, @{Name='FolderDepth';Expression={($_.fullname.Split('\').Count) - ($Pwd.Path.split('\').count)}} | Sort-Object -Descending FullName,folderDepth 
$basefolders = $filtered | Where-Object{$_.folderdepth -eq 1}
$basefoldersobj = @()
foreach($basefolder in $basefolders)
{
  $basefoldername =$baseFolder.fullname
  $filteredbase = $filtered -match "\$basefoldername\\" | Sort-Object -Descending FolderDepth | Select-Object -first 1
  if($filteredbase -eq $null)
  {
    $filteredbase = $filtered -match "\$basefoldername" | Sort-Object -Descending FolderDepth | Select-Object -first 1
  }
  $obj = New-Object psobject
  Add-Member -InputObject $obj -MemberType NoteProperty -Name 'Folder' -Value $basefolder.fullname.trim('\')
  Add-member -InputObject $obj -MemberType NoteProperty -Name 'DeepestPath' -Value $filteredbase.folderDepth
  $basefoldersobj += $obj
}
$include = '*.*'
foreach($bfolderObj in $basefoldersobj)
{
  $includecount = ''
  $includecount = "\$include" * ($bfolderObj.Deepestpath)
  Write-Output "<content Include=`"$($bfolderObj.folder)$includecount`" /> "
}

这应该在powershell提示符下产生必要的include语句


2

您可以添加具有以下链接的文件,它们是可搜索的,可查看的,但是如果您尝试更改它们,它们不会签出,而且visual studio会将通配符保留在适当的位置:

  <ItemGroup>
    <Content Include="..\Database Schema\Views\*.sql">
      <Link>Views\*.sql</Link>
    </Content>
  </ItemGroup>

这位于.proj文件中。


1
我试过了,当我使用VS添加或删除文件时,VS确实用单个文件替换了通配符。
carlin.scott 2015年

这非常优雅,但是您应该从链接目标中删除通配符
SimSimY 2015年

1

据我所知;但是我的建议是将它们粘贴到项目中,因为默认情况下将包括它们。因此,不要通过Explorer将它们粘贴到目录中,而应使用Visual Studio将文件粘贴到文件夹中。


-1

我意识到最好的解决方案是手动添加文件,一个接一个。如果像我一样有数百个,那只需要几个小时。有趣的是,即使在2016年与VS 2015中,这个严重的问题仍然没有解决。啊,我多么爱Xcode。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.