Search code examples
.netvisual-studioconfigurationcsproj

How does project item metadata "PreserveNewest" actually work?


In my .csproj file I've added the following config:

<ItemGroup>
    <None Include="$(USERPROFILE)\.nuget\packages\microsoft.data.sqlclient.sni\1.0.19235.1\buildTransitive\net46\x64\SNI.dll">
        <!-- This is a workaround to include SNI.dll in the NuGet package resulting from the pipeline in Azure DevOps. -->
        <Link>x64\SNI.dll</Link>
        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </None>
</ItemGroup>

But, it's been difficult to find documentation on how PreserveNewest actually works. I've looked at various Stackoverflow posts, and found this page from the documentation, which states under the section for the None element:

CopyToOutputDirectory Optional string. Determines whether to copy the file to the output directory. Values are:

  1. Never
  2. Always
  3. PreserveNewest

It's doesn't really describe how it works. Does anyone know this? By what criteria does it decide what is newest? File changed date? Other version metadata? What does it mean by "preserve"?

The aim of the config is to copy the SNI.dll file to the bin/x64 directory, which it does successfully.


Solution

  • It is based on file modification timestamps. Even looking at the responsible source code is a bit obscure since MSBuild uses Inputs/Outputs of targets to determine if a part of the build logic needs to be executed.

    So if you modify the source file on disk, the next MSBuild run will compare the timestamp to the timestamp of the expected file in the output directory and will only execute that logic if the destination file is missing or has the same or a newer modification date.

    This means that it is preferably to select PreserveNewest if you don't expect the file to change in the target directory (e.g. database file that is modified when the app is started) over Always for two reasons:

    • Less disk IO needed to copy possibly large files
    • VS Project system will not consider projects "up to date" if it has any item set to Always - which means a "Build"/"Run" in VS will always invoke MSBuild and not skip a project if it knows that no files have changed.