【问题标题】:Understanding .NET Core csproj actions了解 .NET Core csproj 操作
【发布时间】:2019-06-09 06:42:04
【问题描述】:

我正在尝试复制文件夹的内容以构建输出。理想情况下,在相对于输出/发布文件夹的相同路径下。我有:

<!-- front-end files to serve -->
<ItemGroup>
  <Folder Include="Frontend\Content">
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>
  </Folder>
</ItemGroup>

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

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

<ItemGroup>
  <None Remove="my-config.json" />
</ItemGroup>
<ItemGroup>
  <Content Include="my-config.json">
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>
  </Content>
</ItemGroup>

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

我模糊的直觉是元素相当于一个“集合”,其内容将根据该元素/集合的名称进行操作,并且包含、排除、删除以某种方式(?)交互以定义和细化该集合的内容。

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

在文档方面,我发现:

https://docs.microsoft.com/en-us/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/en-us/visualstudio/msbuild/msbuild-project-file-schema-reference?view=vs-2017 处的 MSBuild 文档,但这似乎对此毫无用处:它没有记录 NoneEmbeddedResourceCompile 显示的元素,也没有谈论 ContentFolder 我在其他示例中找到的元素(并由 VS 生成)。

事实上,我还没有找到任何关于这一切意味着什么的东西。

我在哪里可以找到这方面的文档?

【问题讨论】:

  • 没有疯狂。这就是 Visual Studio 始终 的工作方式。构建操作为Content 的文件将被发布。其他文件没有。如果您尝试发布“经典” ASP.NET Web 应用程序,您将获得相同的行为。 CopyToOutputDirectory 的意思就是,应该将某些内容复制到配置的输出目录(bin/debug 或 bin/release)。它不会影响文件的类型、构建操作或是否应该打包或发布
  • 您无需在 Content 元素中添加 CopyToOutputDirectory 即可发布它
  • 顺便说一句,这些东西自 2002 年以来在 IDE 文档、操作指南的分步演练、教程和课程中得到了广泛的记录。部署像 jscss 文件这样的内容对于任何 Web 应用程序都至关重要。检查例如Build Actions
  • @PanagiotisKanavos 你能回答我提出的任何问题吗?为什么我的复制任务不起作用?各种集合和动作如何相互作用?如果需要无/删除?文档在哪里?那里的链接没有涵盖大部分内容?
  • (另外——“没有疯狂。这就是 Visual Studio 一直以来的工作方式”——它们并不相互排斥)

标签: .net-core msbuild


【解决方案1】:
  1. 文件夹项目

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

在构建期间不使用&lt;Folder&gt; 项目。复制项目是根据在已知项目类型(无、内容、...)上指定的元数据确定的,而不是基于文件系统层次结构中的文件夹项目。

如果你想为整个层次结构指定元数据,你可以做一个

<Content Include="my/content/**/*" CopyToPublishDirectory="True" … />
  1. 包括/删除组合

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

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

这意味着如果你这样做

<None Include="foo.txt" />
<Content Include="foo.txt" />

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

如果foo.txt 被列为NoneContentEmbeddedResource,那么 IDE(VS、Rider、VS/Mac 等)工具必须做出艰难的决定来决定向您展示什么文件。

为缓解此问题,最好确保将文件仅列为这些“构建操作”项类型之一,这样 IDE 就不会被混淆(以及传递给用户)。

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

新的“SDK 风格”项目添加了很多默认值。它们基本上包含类似(简化的!!):

<None Include="**/*" />

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

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

<None Update="some/content/**/*" CopyToOutputDirectory="True" />
  1. 那么&lt;ItemGroup&gt;下的那些东西是做什么的呢?

这些定义本身没有任何作用。他们只是填充/更改“项目”的集合。 您甚至可以创建自己的并在以后使用它们:

<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>

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

计算编译器输入的部分将查看CompileEmbeddedResource 项,确定将哪些文件复制到输出目录的部分将查找各种项(NoneContentEmbeddedResource 和其他一些 IIRC)具有特定的元数据集。

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

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

【讨论】:

  • 谢谢,这确实很有帮助。请问-FolderNone 有何不同/为什么&lt;CopyToOutputDirectory&gt;Always&lt;/CopyToOutputDirectory&gt;Folder 没有任何作用?似乎所有或大多数其他目标都一致地支持此属性。他们每个人都重复他们对这个功能的实现吗?
  • 没有任何构建逻辑来处理它们。对于 None/Content/EmbeddedResource/BaseApplicationManifest 有 AssignTargetPaths MSBuild target 确定将它们复制到哪里,创建一些中间项,然后 GetCopyToOutputDirectoryItems 使用这些来创建最终集
  • _CopyOutOfDateSourceItemsToOutputDirectory 等目标然后使用这些集合来完成它们的工作。这些目标是 CopyFilesToOutputDirectory target 的依赖项。
  • 除此之外,无论您想复制什么,您都需要构建额外的逻辑以集成到此管道中。
  • 对我来说,这很关键,原因有两个:(1) &lt;Content /&gt; 节点上的属性在 &lt;Content&gt;&lt;CopyToOutputDirectory&gt;... 没有工作时起作用;(2) 它帮助我意识到一些变量可能在解决方案级别定义不一定存在,所以尽量不要使用它们!
猜你喜欢
  • 1970-01-01
  • 2022-12-17
  • 2011-06-15
  • 2018-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多