了解.NET Core csproj操作

Kie*_*one 3 msbuild .net-core

我正在尝试复制文件夹的内容以生成输出。理想情况下,相对于output / publish文件夹位于同一路径下。我有:

<!-- front-end files to serve -->
<ItemGroup>
  <Folder Include="Frontend\Content">
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>
  </Folder>
</ItemGroup>
Run Code Online (Sandbox Code Playgroud)

但是,当我使用时dotnet publish,没有文件被复制。

这适用于我想要的配置文件-这是由VS生成的:

<ItemGroup>
  <None Remove="my-config.json" />
</ItemGroup>
<ItemGroup>
  <Content Include="my-config.json">
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>
  </Content>
</ItemGroup>
Run Code Online (Sandbox Code Playgroud)

所以我的问题是-这是什么疯狂?从语义上说,一个None带有Remove属性的元素-这甚至意味着什么?

我的直觉是元素等同于“集合”,其内容将基于该元素/集合的名称进行操作,并且包含,排除,删除某种方式(?)相互作用以定义和完善内容那个。

但是,那么-什么是“文件夹”?什么是“内容”?当事情加倍时会发生什么:为什么需要“无/删除”组合?如果有的话-那是由VS生成的!

在文档方面,我发现:

https://docs.microsoft.com/zh-cn/dotnet/core/tools/csproj#how-to-see-the-whole-project-as-msbuild-sees-it,其中介绍了Compile,EmbeddedResource和None默认Glob(包括,排除和删除Glob)。我知道什么是glob,我知道这些动作的含义,但是这些glob的类型是什么?他们如何互动?

它还指向https://docs.microsoft.com/zh-cn/visualstudio/msbuild/msbuild-project-file-schema-reference?view=vs-2017的 MSBuild文档,但这似乎无济于事:它没有既没有显示文档None,EmbeddedResource或Compile元素,也没有谈到我在其他示例中找到的Content和Folder元素(由VS生成)。

实际上,我还没有发现有关这一切的任何信息。

在哪里可以找到相关文档?

Mar*_*ich 6

  1. 文件夹项目

<Folder>在VS内部使用只是在解决方案资源管理器中显示一个节点,例如,使您指向右键单击“添加>新建...”。wwwroot是ASP.NET Core应用程序的经典示例,但是如果您使用VS的“添加>新建文件夹”功能或删除现有文件夹中的所有文件,它将添加一个节点以将其保留在解决方案资源管理器中。

这些<Folder>项目在构建过程中不使用。复制项目是根据在已知项目类型(无,内容等)上指定的元数据确定的,而不是基于文件系统层次结构中的“文件夹”项目确定的。

如果您想为整个层次结构指定元数据,则可以执行

<Content Include="my/content/**/*" CopyToPublishDirectory="True" … />
Run Code Online (Sandbox Code Playgroud)
  1. 包含/删除组合

在项目文件的静态内容内(不在其中<Target>-适用于一些不同的规则),MSBuild允许对项目集合进行三种操作:

  • 包括:将一个项目添加到指定项目类型的项目的“集合”中
  • 更新:更改指定项目类型的项目的元数据
  • 删除:从“收藏夹”中删除项目

这意味着如果您这样做

<None Include="foo.txt" />
<Content Include="foo.txt" />
Run Code Online (Sandbox Code Playgroud)

然后,@(None)和@(Content)集合都将包含foo.txt。对于构建系统来说,这并不是真正的问题(除非您指定要将它们都复制到输出中-这会导致输出路径冲突而导致错误),但是对于显示项目中文件及其属性的工具而言,会造成棘手的情况。

如果foo.txt列为None,Content和EmbeddedResource,则IDE(VS,Rider,VS / Mac等)工具必须对显示该文件的内容做出艰难的决定。

为了缓解此问题,最好确保将文件仅列为这些“生成操作”项类型之一,以免IDE引起混淆(也可以传递给用户)。

那么,为什么必须从中删除文件None?

新的“ SDK风格”项目添加了许多默认设置。它们基本上包含类似(简体!)的内容:

<None Include="**/*" />
Run Code Online (Sandbox Code Playgroud)

因此,如果要将文件更改为嵌入式资源或内容项,则应从@(None)集合中删除该文件。

如果您不需要更改商品类型,也可以使用Update:

<None Update="some/content/**/*" CopyToOutputDirectory="True" />
Run Code Online (Sandbox Code Playgroud)
  1. 那么这些事情在<ItemGroup>做什么呢?

这些定义本身无能为力。他们只是填充/更改“项目”的集合。您甚至可以创建自己的,以后再使用:

<MyCoolFiles Include="cool/files/**/*;other/cool/files/**/*" />
<None Remove="@(MyCoolFiles)" />
<Content Include="@(MyCoolFiles)" CopyToPublishDirectory="True" />

<Target Name="PrintCoolFiles" BeforeTargets="BeforeBuild">
  <Message Importance="high" Text="These are my cool files: @(MyCoolFiles)" />
</Target>
Run Code Online (Sandbox Code Playgroud)

关键是构建逻辑的某些部分会查找并使用它们知道的项目。

计算输入到编译器将着眼于部分Compile和EmbeddedResource项目,部分是确定哪些文件复制到输出目录会寻找各种项目(None,Content,EmbeddedResource和其他几个人IIRC)与特定的元数据集。

新项目类型可以定义自己的项目类型,以通过可扩展性点在VS的解决方案资源管理器中列出。

但是VS只会在解决方案资源管理器中显示以这种方式配置的项目类型的项目。对于这些项目类型,最好不要列出多个文件。