了解.NET Core csproj操作

时间:2019-01-15 09:10:29

标签: .net-core msbuild

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

<!-- 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(包括,Exclude和Remove Glob)。我知道什么是glob,我知道这些动作的含义,但是这些glob的类型是什么?他们如何互动?

它也指向位于https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-project-file-schema-reference?view=vs-2017的MSBuild文档,但这似乎没有用:它没有记录NoneEmbeddedResourceCompile元素,也没有文档它是否讨论了我在其他示例中找到的(由VS生成的)ContentFolder元素。

实际上,我什么都没发现,这都意味着什么。

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

1 个答案:

答案 0 :(得分:2)

  1. 文件夹项目

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

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

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

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

在项目文件的静态内容内(不在<Target>中-此处适用一些不同的规则),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. <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>

关键点在于,构建逻辑的某些部分会查找并了解它们所使用的项目。

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

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

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