我经常向我的 ASP.NET 项目添加大量内容文件(主要是图像和 js)。我正在使用 VS 发布系统,并且在发布时,新文件在我将它们包含在项目中之前不会发布。我想自动包含指定目录中的所有文件。有没有办法指定哪些目录应该自动包含在 csproj 文件或其他任何地方?
8 回答
旧线程,我知道,但我找到了一种我一直忘记的方法,并且在我最后一次寻找它时,我偶然发现了这个问题。我发现最好的方法是在 .csproj 文件中使用 BeforeBuild 目标。
<Target Name="BeforeBuild">
<ItemGroup>
<Content Include="**\*.less" />
</ItemGroup>
</Target>
VS 2010 不会涉及此部分,它确保每次构建项目时您的文件都作为内容包含在内。
您只需扩展您的网站 .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 中的内容项一起发布,所以我没有在我的回答中提出它。
对于那些使用Chris' answer有问题的人,这是 Visual Studio 2012 及更新版本的解决方案:
<Target Name="ContentsBeforeBuild" AfterTargets="BeforeBuild">
<ItemGroup>
<Content Include="images\**" />
</ItemGroup>
</Target>
正如 Chris 在他的回答中提到的那样 - Visual Studio不会触及这一<Target>
部分,即使您手动摆弄(添加/删除文件)与目标目录。
请注意,您应该包含文件所在的子目录(在上述情况下,它是images
)。Visual Studio/MSBuild 会将这些文件放在项目结构中的同一目录中。如果不使用子目录,文件将放置在项目结构的根目录下。
对于通配符的快速解释:
**
递归表示一切(文件、子目录和其中的文件)*.ext
ext
将包括顶级目录中 所有带扩展名的文件,但不包括子目录- 例如,
*.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>
您可以使用框架的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>
我已经写了如何获得使用小型 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 语句
您可以使用这样的链接添加文件,它们是可搜索的、可查看的,但如果您尝试更改它们,它们不会检出,Visual Studio 也会保留通配符:
<ItemGroup>
<Content Include="..\Database Schema\Views\*.sql">
<Link>Views\*.sql</Link>
</Content>
</ItemGroup>
这在 .proj 文件中。
据我所知,不是;但是我的建议是将它们粘贴到项目中,因为这将默认包含它们。因此,不要通过资源管理器将它们粘贴到目录中,而是使用 Visual Studio 将文件粘贴到文件夹中。
我意识到最好的解决方案是手动添加文件,一个一个。如果您像我一样拥有数百个,那么这只是几个小时的问题。有趣的是,即使在 2016 年使用 VS 2015,这个严重的问题仍然没有解决。啊,我多么喜欢 Xcode。