【问题标题】:What is the difference between "none include" and "none update" in SDK-style csproj projects?SDK风格的csproj项目中的“none include”和“none update”有什么区别?
【发布时间】:2020-02-24 00:10:24
【问题描述】:

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

This article 建议使用“无更新”

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

this stackoverflow answer 建议使用“none include”:

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

updateinclude 有什么区别?

【问题讨论】:

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


    【解决方案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.适用于 .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.-->
    

    包含 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 仅用于更新一个项目的元数据。它没有包含某些文件的功能。只有当一个文件已包含在一个项目中时,它才会起作用。

    澄清在.net core 控制台中使用Update + appsettings.jsonasp.net core网络应用:

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

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

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

    但是对于脚本&lt;None Update="appsettings.json" CopyToOutputDirectory="PreserveNewest" /&gt;,它只有在项目文件中没有&lt;Content xxx="appsettings.json"...&gt;这样的语句时才有效。

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

    如果我们将build action设置为None,将Copy to Output设置为Copy if NeverCopy if Never,在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>
    

    更新2:

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

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

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

    更新3:

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

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

    <None Include="appsettings.json" CopyToOutputDirectory="Never" /> 
    

    这就是为什么None+Include+Always(覆盖)和None+Update+Always or PreserveNewest(修改元数据)都适用于复制行为。它可以描述为什么默认情况下该文件不会被复制,即使 VS 在某处隐藏了None+Include 定义。因为CopyToOutputDirectory默认设置为从不。

    【讨论】:

    • 你说update Enables you to modify metadata of a file that was included by using a glob. 当我使用更新 sn-p 时,我确认 appsettings.json 被复制到输出文件夹中,而之前它不存在。我还确认如果源 appsettings.json 中的内容发生更改,则 bin 目录中的副本会在构建后更新。所以它似乎不仅仅是为了更新元数据?
    • @user453441 对于when it wasn't there before?您是否在 asp.net 核心项目中对其进行测试?请参阅我关于In Asp.net core web application 的声明。这些定义是隐藏的,并且未在 xx.csproj 中明确显示用于 sdk 格式。比较空的 .net 框架控制台和空的 .net 核心控制台中的项目文件内容,您可以看到差异。新的 SDK 格式更加清晰。
    • 不,我正在使用 .net 核心控制台应用程序(目标框架 netcoreapp3.0),并且我正在使用 VS 代码。
    • @user453441 我猜Update2可以帮助解决您的困惑并确认Update的使用。虽然 csproj 中没有显示定义,但我们可以使用 target+message 任务来输出隐藏的定义。希望它有所帮助:)
    • 很抱歉,我很难阅读您的答案,甚至只是单独阅读 Update2 部分。如果我已经有一个“隐藏或未显示”的none includecontent include,这是否意味着即使我不添加我的none update,appsettings.json 也会被复制到输出文件夹中??我赞成你的回答,因为我感谢你帮助研究这个问题。
    猜你喜欢
    • 2014-02-23
    • 2010-11-06
    • 2023-03-17
    • 2018-06-06
    • 2017-10-22
    • 2010-09-06
    • 2017-01-11
    相关资源
    最近更新 更多