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

use*_*441 13 msbuild csproj visual-studio visual-studio-code

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

本文推荐使用“无更新”

<ItemGroup>
    <None Update="appsettings.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
Run Code Online (Sandbox Code Playgroud)

这个计算器的答案建议使用“无有”:

<ItemGroup>
    <None Include="appsettings.json" CopyToOutputDirectory="Always" />
</ItemGroup>
Run Code Online (Sandbox Code Playgroud)

update和 和有include什么区别?

Lan*_*SFT 6

更新和包含有什么区别?

根据这份文件

用法

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.适用于.net核心项目

2.在VS2017及以后可用

3.在 Target 内的 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.-->
Run Code Online (Sandbox Code Playgroud)

包含 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>
Run Code Online (Sandbox Code Playgroud)

所以很明显,Update attribute它仅用于更新一个 Item 的元数据。它没有包含某些文件的功能。并且仅当一个文件包含在一个项目中时才有效。

Update + appsettings.json.net core控制台和 asp.net coreWeb 应用程序中使用时要澄清一些事情:

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

如果您创建一个新asp.net core web项目,appsettings.json默认情况下xx.csproj您可以在解决方案资源管理器中看到该文件。但是如果您阅读了您在那里找不到定义,则定义未明确显示在xx.csprojsdk 格式中。

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

但是对于 script <None Update="appsettings.json" CopyToOutputDirectory="PreserveNewest" />,它只有<Content xxx="appsettings.json"...>在项目文件中没有类似的语句时才有效。

我建议您通过 VS UI 来执行此操作,而不是手动编辑 xx.csproj。我们可以更改Build Action and Copy To Output设置Property Window

在此处输入图片说明

如果我们将 设置build actionNone,并将复制到输出设置Copy if NeverCopy Always,则在 xx.csproj 中我们可以找到:

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

  <ItemGroup>
    <None Include="appsettings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
  </ItemGroup>
Run Code Online (Sandbox Code Playgroud)

所以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>
Run Code Online (Sandbox Code Playgroud)

更新2:

我只是做了一些测试,发现即使在 VS 中的 .net core 控制台项目中,虽然 csproj 中没有定义,但更新可以工作。奇怪的?

最后我发现这是因为该定义隐藏或未显示在 csproj 文件中,实际上当您在项目中有一个 appsettings.json 文件时,您已经有一个已<None Include="appsettings.json"...定义的(有时是 Content+include,ikt 取决于您添加的方式该文件),虽然这在 csproj 中是无效的,请看我的截图:

在此处输入图片说明

这就是为什么 Update 可以用于复制行为,尽管它用于修改元数据。在我们使用 Update 之前,None+Include+Appsettings.json虽然 csproj 中没有显示,但已经存在定义。(sdk 格式)

更新3:

我对 Update1 中的脚本做了一些小改动以显示<None Include="appsettings.json">的元数据。

在此处输入图片说明

所以在 .net core 控制台项目中,appsettings.json文件默认是

<None Include="appsettings.json" CopyToOutputDirectory="Never" /> 
Run Code Online (Sandbox Code Playgroud)

这就是None+Include+Always(Overwrite) 和None+Update+Always or PreserveNewest(Modify the metadata) 都适用于复制行为的原因。它可以描述为什么默认情况下即使 VS 在None+Include某处有隐藏定义,该文件也不会被复制。因为CopyToOutputDirectory默认设置为从不。