SDK风格的csproj项目中的“无包含”和“无更新”有什么区别?

时间:2019-10-28 17:37:10

标签: visual-studio visual-studio-code msbuild csproj

我一直在寻找正确的方法来确保在构建项目时将appsettings.json复制到bin目录中。

This article建议使用“无更新”

<ItemGroup>
    <None Update="appsettings.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

并且this stackoverflow answer建议使用“无包含”:

<ItemGroup>
    <None Include="appsettings.json" CopyToOutputDirectory="Always" />
</ItemGroup>

updateinclude有什么区别?

1 个答案:

答案 0 :(得分:1)

  

更新和包含有什么区别?

根据this document

用法

Include属性=>要包含在项目列表中的文件或通配符。

Update属性=>使您能够修改使用glob包含的文件的元数据。

工作范围:

Include attribute

1。适用于normal .net framewrok(非SDK格式),.net core and .net standard(SDK格式)以及C ++项目...

2。用于许多VS版本(据我所知,从VS2010到VS2019)

3。Include即使在Targets中的ItemGroup中也有效

Update attribute

1.Works for .net核心项目

2。在VS2017及更高版本中可用

3。在目标内的ItemGroup中使用它时不支持

测试和结果:

不包含c.txt时进行首次测试:

  <ItemGroup>
    <DoSth Include="a.txt"/>
    <DoSth Include="b.txt"/>
    <DoSth Update="c.txt" Metadata="test"/>
  </ItemGroup>

  <Target Name="MyTest" AfterTargets="build">
    <Message Text="@(DoSth)" Importance="high"/>
  </Target>
  <!--The output is a.txt and b.txt, no c.txt.-->

包含c.txt的第二次测试:

  <ItemGroup>
    <DoSth Include="a.txt"/>
    <DoSth Include="b.txt"/>
    <DoSth Include="c.txt" Metadata="original"/>
    <DoSth Update="c.txt" Metadata="test"/>
  </ItemGroup>

  <Target Name="MyTest" AfterTargets="build">
    <Message Text="@(DoSth)" Importance="high"/> <!--The output files are a.txt,b.txt and c.txt.-->
    <Message Text="%(DoSth.Identity)+%(DoSth.Metadata)" Importance="high"/>  <!--The output Metadata of c.txt is test instead of original-->
  </Target>

因此,很明显Update attribute仅用于更新一个项目的元数据。它没有包含某些文件的功能。而且只有在一个项目中包含一个文件时,它才起作用。

  

要澄清在Update + appsettings.json控制台中使用.net core时的某些情况,   asp.net core网络应用程序:

在Asp.net核心Web应用程序中:

如果您创建一个新的asp.net core web项目,则默认情况下可以在解决方案资源管理器中看到appsettings.json文件。但是,如果您阅读了xx.csproj,则无法在其中找到定义,对于{sdk格式,xx.csproj中没有明确显示定义。

在这种情况下,如果我们使用诸如<None Include="appsettings.json" CopyToOutputDirectory="Always" />之类的脚本,则始终可以将该文件复制到输出。

但是对于脚本<None Update="appsettings.json" CopyToOutputDirectory="PreserveNewest" />,它仅在项目文件中没有像<Content xxx="appsettings.json"...>这样的语句时才起作用。

我建议您通过VS UI进行操作,而不要手动编辑xx.csproj。我们可以在Build Action and Copy To Output中更改Property Window的设置:

enter image description here

如果将build action设置为None,将“复制到输出”设置为Copy if Never中的Copy Always,则在xx.csproj中,我们可以找到:

  <ItemGroup>
    <Content Remove="appsettings.json" />
  </ItemGroup>

  <ItemGroup>
    <None Include="appsettings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
  </ItemGroup>

因此,VS为此使用了None + Include。综上所述,我建议您在项目中使用None+Include而不是None+Update。另外,最推荐的方法是在VS IDE中通过UI控制复制行为,而不是手动编辑。希望以上所有对您有所帮助:)

更新1:

我们可以将此脚本添加到项目文件中,以输出有关csproj中未显示的None Items和Content Items的信息:

  <Target Name="TrytoFindDefinitionsNowShown" AfterTargets="build">
    <Message Text="None: @(None)" Importance="high"/>
    <Message Text="Content: @(Content)" Importance="high"/>
  </Target>

Update2:

我只是做了一些测试,甚至在VS中的.net核心控制台项目中也找到了,尽管csproj中没有定义,但该更新可以正常进行。奇怪?

最后我发现这是因为该定义在csproj文件中被隐藏或未显示,实际上,当您在项目中有一个appsettings.json文件时,您已经有一个{{1} }定义(有时Content + include,ikt取决于您添加该文件的方式),尽管在csproj中看不到,但请参见我的屏幕截图:

enter image description here

所以这就是为什么Update可以用于复制行为的原因,尽管它用于修改元数据。在使用更新之前,虽然csproj中没有显示定义<None Include="appsettings.json"...,但已经存在。 (对于sdk格式)

Update3:

我对Update1中的脚本做了一些小的更改,以显示None+Include+Appsettings.json的元数据。

enter image description here

因此,在.net核心控制台项目中,<None Include="appsettings.json">文件默认为

appsettings.json

这就是<None Include="appsettings.json" CopyToOutputDirectory="Never" /> (覆盖)和None+Include+Always(修改元数据)都可以实现复制行为的原因。它可以说明为什么默认情况下即使VS在某个地方隐藏了None+Update+Always or PreserveNewest定义也不会复制该文件。因为默认情况下None+Include设置为“从不”。