【问题标题】:Is there a way to automatically include content files into asp.net project file?有没有办法自动将内容文件包含到 asp.net 项目文件中?
【发布时间】:2011-02-02 19:30:54
【问题描述】:

我经常向我的 ASP.NET 项目添加大量内容文件(主要是图像和 js)。我正在使用 VS 发布系统,并且在发布时,新文件在我将它们包含在项目中之前不会发布。我想自动包含指定目录中的所有文件。有没有办法指定哪些目录应该自动包含在 csproj 文件或其他任何地方?

【问题讨论】:

标签: asp.net msbuild csproj


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    您只需扩展您的网站 .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 中的内容项一起发布,所以我没有展示它在我的回答中。

    【讨论】:

    • 在我手动添加或删除文件之前它一直有效。在该行之后 从项目文件中消失。
    • @Marko 是正确的。添加&lt;Content Include="Images\**\*.*" /&gt; 后,它起作用了。添加更多图像后, .csproj 将更改并返回到列出 images/ 中的所有文件...并且 消失了。跨度>
    • 将此代码粘贴在单独的 .proj 文件中,然后从 .csproj 文件中的构建目标之前调用它。
    【解决方案3】:

    旧线程,我知道,但我找到了一种我一直忘记的方法,并且在我最后一次寻找它时,我偶然发现了这个问题。我发现最好的方法是在 .csproj 文件中使用 BeforeBuild 目标。

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

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

    【讨论】:

    • .less是什么意思?整个字符串 **\*.less 是什么意思?
    • .less 文件是旨在由 Less CSS 预处理器解析的 css 文件。谷歌“少点”以获取更多信息。表达式**\*.less 表示在所有目录中包含所有 *.less 文件。在 MSBUILD 中,** 表示“递归所有目录”
    • 至少在 VS 2012 中,一旦您从项目中添加/删除文件并保存,不幸的是,这会扩展到完整列表。 :(
    • 这仅在将 BeforeBuild 更改为 AfterBuild 后才适用于我的情况,我的构建启动了一个移动文件的 powershell 脚本,然后我的 azure web deploy 尝试不会拾取该脚本,因为它们只存在于之后构建成功。看到“BeforeBuild”让我意识到可能还有一个“AterBuild”。希望这对其他人有帮助。
    • @John 请参阅 my answer below 以获得 VS2015+ 的修复。
    【解决方案4】:

    您可以使用这样的链接添加文件,它们是可搜索的、可查看的,但如果您尝试更改它们,它们不会检出,Visual Studio 也会保留通配符:

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

    这在 .proj 文件中。

    【讨论】:

    • 我试过了,当我使用 VS 添加或删除文件时,VS 确实将通配符替换为单个文件。
    • 这很优雅,但你应该从链接目标中删除通配符
    【解决方案5】:

    您可以使用框架的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>
    

    【讨论】:

    • 这对我帮助很大;我有多个深几级的目录和许多我想要自动包含的文件,这将所有这些内容合二为一。谢谢!
    • 我对此进行了更多试验,结果发现这与带有通配符的Include="**\*.ext" 具有相同的限制。
    • 哇,项目文件是否包含运行powershell?那是沙盒吗?这是一个等待发生的漏洞。
    • 这不是 PowerShell。 MSBuild 有自己的用于调用静态方法的语法。根据文档,这仅限于系统类。 docs.microsoft.com/en-us/visualstudio/msbuild/… 虽然我确信你可以使用任何参数来 powershell ...
    【解决方案6】:

    我已经写了我是如何获得使用小型 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 提示符下生成必要的包含语句

    【讨论】:

      【解决方案7】:

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

      【讨论】:

        【解决方案8】:

        对于那些在使用 Chris' answer 时遇到问题的人,这是 Visual Studio 2012 及更高版本的解决方案:

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

        正如 Chris 在他的回答中提到的那样 - Visual Studio 不会触及这个 &lt;Target&gt; 部分,即使您手动摆弄(添加/删除文件)与目标目录。

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

        对于通配符的快速解释:

        • ** 表示一切递归(文件、子目录和其中的文件)
        • *.ext 将包含顶级目录中所有扩展名为 ext 的文件,但不包含子目录
          • 例如,*.ext 可以是 *.png*.js 等。任何文件扩展名都可以使用
        • **\*.ext 将包含顶级目录和所有子目录中扩展名为 ext 的所有文件。
        • 请参阅How do I use Nant/Ant naming patterns? 的答案以获取更完整的示例说明。

        为了补全,请注意使用&lt;Target&gt;和不使用是有区别的。

        使用&lt;Target&gt; 方法,Visual Studio 不会在解决方案资源管理器中显示文件。

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

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

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

        【讨论】:

        • 感谢您尝试并指出使用 与不使用之间的区别。通配符的详细说明也很好。
        • @KurtHutchinson - 没问题。 =)
        • 我相信这个解决方案需要完善。当您指示目标在“BeforeBuild”之后运行时,理论上这也可能在发布之后发生。当前的解决方案可能由于运气而起作用。
        • @ImrePühvel 你如何看待发布发生在BeforeBuild 事件之前? MSBuild 必须首先构建项目和二进制文件,然后才能考虑发布。
        • 我并没有声称发布是在构建之前发生的,但该声明并不能保证项目在发布之前添加到内容中。来自代码示例:.. AfterTargets="BeforeBuild"。意思是,你的自定义目标必须在 BeforeBuild 之后执行,但它没有指定之后的多少。不过,我的错误,按照当前的目标排序算法应该没问题:msdn.microsoft.com/en-us/library/ee216359.aspx
        猜你喜欢
        • 2017-06-02
        • 1970-01-01
        • 2012-11-18
        • 2014-01-21
        • 2012-04-15
        • 2016-08-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多