Search code examples
c#.netvisual-studionuget

Can't set 'Copy Always' for dll imported from nuget using .targets file


I have a library that gets imported to another project via nuget. However, in the target project, the 'Copy to Output Directory' is always set to 'Do not copy'. This happens even if I had previously set it to 'Copy Always' and I do an update; it resets it to 'Do Not Copy'. I want it to be 'Copy Always', (or at the very least keep the previous setting following an update).

To achieve this, I tried creating a .targets file as described in the following questions:

Set content files to "copy local : always" in a nuget package and How can I set the 'copy to output directory' property in my nuspec file?

However, it doesn't seem to do it for me and I'm not sure that my scenario is the exact same as described in those questions.

What ends up in the .csproj file of the target project is:

<Content Include="Assets\Devices\MyProj.Devices.Test.NugetTesting.dll" />

whereas what I want is

<Content Include="Assets\Devices\MyProj.Devices.Test.NugetTesting.dll">
  <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>

my nuspec file is:

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
  <metadata>
    <version>$version$</version>
    <authors>komodosp</authors>
    <owners>komodosp</owners>
    <id>MyProj.Devices.Test.NugetTesting.dll</id>
    <title>MyProj.Devices.Test.NugetTesting</title>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Device implementation library for nuget testing</description>
    <copyright>Copyright komodosp 2024</copyright>
    <dependencies>
      <dependency id="MyProj.Devices.Interfaces" version="2.0.*" />
    </dependencies>
  </metadata>
  <files>
    <file src="MyProj.Devices.Test.NugetTesting.targets" target="Build\" />
    <file src="bin\Release\MyProj.Devices.Test.NugetTesting.dll" target="content\Assets\Devices" />
  </files>
</package>

My targets file - which I've placed in the 'root' of the project's directory (i.e. same dir as the csproj file) and called MyProj.Devices.Test.NugetTesting.targets is:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <None Include="$(ProjectDir)content\Assets\Devices\MyProj.Devices.Test.NugetTesting.dll">
      <Link>MyProj.Devices.Test.NugetTesting.dll</Link>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None> 
  </ItemGroup>
</Project>

(... as described in the above linked questions)

also, following the thinking that I shouldn't be using <None> if I want it as a <Content> in the target .csproj file, I've also tried this .targets file:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Content Include="$(ProjectDir)\content\Assets\Devices\MyProj.Devices.Test.NugetTesting.dll">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
  </ItemGroup>
</Project>

If I download the.nupkg file and unzip it, I can see the .targets file is there in the Build dir. However, in visual studio, when I restore the package, I don't see any mention of the .targets file in the log in the output tab (not sure if there should be), so I don't even know if it's looking at it.

In the end, the dll always updates into the correct location, but with 'Copy to Output Directory' set to 'Do not copy'.


Solution

  • Turns out I had been misunderstanding how a .targets file is imported into the client project.

    It does not cause the <Content> in the project itself to be updated, and so the property, when viewed in Visual Studio does not reflect the new setting and remains at 'Do Not Copy'.

    However, because the .targets file is imported into the .csproj with an <Import> tag that gets automatically added, the file still ends up being copied to the build output.

    For the record, there was also a mistake in my .targets file - here is the one that I ended up using and worked. (i.e. no need for 'content' in the file path)

    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <ItemGroup>
        <Content Include="$(ProjectDir)\Assets\Devices\MyProj.Devices.Test.NugetTesting.dll">
          <CopyToOutputDirectory>Always</CopyToOutputDirectory>
        </Content>
      </ItemGroup>
    </Project>
    

    Thanks to a comment on this answer by Martin Christiansen