Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between "none include" and "none update" in SDK-style csproj projects?

I was looking for the correct way to ensure appsettings.json is copied to the bin directory when building my project.

This article recommends using "none update"

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

And this stackoverflow answer recommends using "none include":

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

What is the difference between update and include?

like image 750
user453441 Avatar asked Oct 28 '19 17:10

user453441


People also ask

What is none include in Csproj?

None - The file is not included in the project output group and is not compiled in the build process. An example is a text file that contains documentation, such as a Readme file. Content - The file is not compiled, but is included in the Content output group.

What is a Csproj file?

What is a CSProj file? Files with CSPROJ extension represent a C# project file that contains the list of files included in a project along with the references to system assemblies.


1 Answers

What is the difference between update and include?

According to this document:

Usage:

Include attribute => The file or wildcard to include in the list of items.

Update attribute => Enables you to modify metadata of a file that was included by using a glob.

Working Scope:

Include attribute:

1.Works for both normal .net framewrok(non-sdk format), .net core and .net standard(sdk format), also C++ projects...

2.Used in many VS versions(As I know, from VS2010 to VS2019)

3.Include works even in ItemGroup in Targets

Update attribute:

1.Works for .net core projects

2.Available in VS2017 and later

3.Not supported when using it in an ItemGroup inside a Target

Tests and results:

First Test when c.txt is not included:

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

Second Test when c.txt is included:

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

So it's obvious that Update attribute is only used to update one Item's metadata. It has no function to include some files. And it will only work when one file has been Included in one Item.

To clarify something when using Update + appsettings.json in .net core console and asp.net core web app:

In Asp.net core web application:

If you create a new asp.net core web project, you can see the appsettings.json file in Solution Explorer by default.But if you read the xx.csproj you can't find the definition there, the definitions is not explicitly shown in xx.csproj for sdk-format.

In this situation, if we use script like <None Include="appsettings.json" CopyToOutputDirectory="Always" />, it always works to copy that file to output.

But for script <None Update="appsettings.json" CopyToOutputDirectory="PreserveNewest" />, it works only when there's no statement like <Content xxx="appsettings.json"...> in the project file.

And I recommend you do this by VS UI instead manual editing xx.csproj. We can change the Build Action and Copy To Output Settings in Property Window:

enter image description here

If we set the build action to be None, and Copy to Output to be Copy if Never of Copy Always, in xx.csproj we can find:

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

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

So VS use None+Include behind for this. According to all above, I suggest you use None+Include instead of None+Update in your project. Also, the most recommended way is to control the copy behavior by UI in VS IDE instead of manual editing. Hope all above helps :)

Update1:

We can add this script in project file to output the info about None Items and Content Items that not shown in csproj:

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

Update2:

I just did some tests and find even in .net core console project in VS, though no definitions in csproj, the update can work. Strange?

And finally I found this is because that definition is hidden or not shown in csproj file, actually when you have a appsettings.json file in project, you've already have a <None Include="appsettings.json"... defined(sometimes Content+include, ikt depends on the way you add that file), though that's not valid to see in csproj, see my screenshot:

enter image description here

So that's why Update can work for the copy behavior though it's something used to modify metadata. Before we use the Update, there already exists the definition None+Include+Appsettings.json though that's not shown in csproj. (For sdk format)

Update3:

I did some little changes to script in Update1 to display the <None Include="appsettings.json">'s metadata.

enter image description here

So in a .net core console project, appsettings.json file by default is

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

That's why both None+Include+Always(Overwrite) and None+Update+Always or PreserveNewest(Modify the metadata) work for copy behavior. And it can describe why by default that file won't be copied even VS have hidden None+Include definitions somewhere. Because the CopyToOutputDirectory is set to be Never by default.

like image 123
LoLance Avatar answered Oct 18 '22 23:10

LoLance