在Visual Studio中将通配符包含文件添加到文件夹中

21

我正在使用

<ItemGroup>
  <EmbeddedResource Include="..\..\resources\hbm\*.hbm.xml" />
</ItemGroup>

我想将一批XML文件包含到我的C#项目中。这个方法很好用。

但是,我不希望它们在项目的“根级别”,我更想在项目的子文件夹中看到它们。

例如,这个文件被包含在Visual Studio的“Mapping”文件夹中:

<ItemGroup>
  <EmbeddedResource Include="Mapping\User.hbm.xml" />
</ItemGroup>

这就是我想要的*.hbm.xml文件。

我不知道如何做到这一点,并仍然保持通配符*.hbm.xml部分,同时将实际文件保存在不同的目录中。

我查看了MSDN关于MSBUILD和项目的文档,但没有找到解决方法。

3个回答

46

也许自原回答发布以来,MSBuild已经发生了变化,但是现在可以同时使用通配符和链接。例如,在C#项目中,我使用以下代码块将数据文件导入测试库。

<ItemGroup>
  <None Include="..\SOMENAME.Tests\data\**\*.*">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    <Link>data\%(RecursiveDir)%(Filename)%(Extension)</Link>
  </None>
</ItemGroup>

到目前为止,我所看到的唯一不利之处是MSBuild会重新创建文件系统上的文件夹名称(即$(ProjectPath)\data\somesubfolder),这有点烦人但并不是一个很大的问题。

作为一个测试,我还尝试了OP的请求,使用以下代码片段嵌入资源,同样地,这似乎也能正常工作——dotPeek显示编译后程序集中存在资源,同时在解决方案资源管理器中也存在。

<ItemGroup>
  <EmbeddedResource  Include="..\SOMENAME.Tests\data\**\*.*">
      <Link>resources\%(RecursiveDir)%(Filename)%(Extension)</Link>
  </EmbeddedResource>
</ItemGroup>

(这是使用 Visual Studio 2013,截至 VS2019 仍然有效)

2021年6月8日更新:上述语法适用于旧式 csproj 文件,但如果您正在使用新的 SDK 格式,则语法略有不同,尽管更简单。

使用以下内容可以实现 OP 的原始问题中的通配符嵌入

<ItemGroup>
  <EmbeddedResource Include="data\**\*.*" />
</ItemGroup>

同时对于被更改或丢失的文件进行通配符文件复制。

<ItemGroup>
  <None Update="data\**\*.*">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
</ItemGroup>

我可以确认,这适用于Visual Studio 2015更新3版。 - Andreas Willich
1
仍适用于Visual Studio 2019(16.9.1)中的.Net 5项目。 - Ola Berntsson

9

我认为你不能同时使用链接和通配符。

你可以使用以下符号在Visual Studio中链接到Mapping文件夹中的User.hbm.xml文件:

<ItemGroup>
  <EmbeddedResource Include="..\..\resources\hbm\User.hbm.xml">
    <Link>Mapping\User.hbm.xml</Link>
  </EmbeddedResource>
</ItemGroup>

但是你不能这样做。

<ItemGroup>
  <EmbeddedResource Include="..\..\resources\hbm\**\*.hbm.xml">
    <Link>%(RecursiveDir)\%(Filename)%(Extension)</Link>
  </EmbeddedResource>
</ItemGroup>

我决定编写一个脚本来更新我的 CSPROJ 文件。然后将其添加为 msbuild 脚本中的 Exec 任务。它可以正常工作,但有点棘手。 - quip
愿意分享脚本吗? :-) - Etan

0

我已经能够基于一些正则表达式创建逻辑名称(仅限一个文件夹深度)。我想要的根命名空间是Agility.BmsData.Create,资源的最终名称示例可以是Agility.BmsData.Create.tables.mytable.sql,其中文件位于tables\mytable.sql文件夹中。

    <ItemGroup>
        <EmbeddedResource Include="..\..\AgilityDatabase\Create\**\*.sql" >
            <!-- see https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-well-known-item-metadata?view=vs-2022 -->
            <!--     https://learn.microsoft.com/en-us/visualstudio/msbuild/property-functions?view=vs-2022 -->
            <LogicalName>
                Agility.BmsData.Create.$(
                    [System.Text.RegularExpressions.Regex]::Match("%(Directory)", "(?&lt;=\\)[^\\]+(?=[\\]*$)")
                ).%(Filename)%(Extension)
            </LogicalName>
        </EmbeddedResource>
    </ItemGroup>

也可以自定义 EmbeddedResource 元素的 Link 属性,但该值需要适当编码以嵌入在 xml 属性中。 继续以上示例,我在相对路径上有 sql 文件位于数据库项目中的路径为 ..\..\AgilityDatabase\Create\,并且我想要在我的另一个项目中模拟文件结构(和资源名称)。我可以使用以下 MsBuild 命令 $([System.Text.RegularExpressions.Regex]::Match("%(Directory)", "(?<=\\AgilityDatabase\\Create\\).+$"))\%(Filename)%(Extension)

因此我的 Item 组变成了:

<EmbeddedResource Include="..\..\AgilityDatabase\Create\**\*.sql"
                  Link="Create\$([System.Text.RegularExpressions.Regex]::Match(&quot;%(Directory)&quot;, &quot;(?&lt;=\\AgilityDatabase\\Create\\).+$&quot;))\%(Filename)%(Extension)">
</EmbeddedResource>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接