Home: PackageReference: Need control over the selection for individual .dlls

Created on 4 Oct 2017  路  12Comments  路  Source: NuGet/Home

Details about Problem

NuGet product used (NuGet.exe | VS UI | Package Manager Console | dotnet.exe):
MSBuild 15.3 elements.

VS version (if appropriate):
15.3 or newer

Detailed repro steps so we can see the same problem

I don't see a way to control whether the .dll from PackageReference gets copied to output or not.

Additionally, if I have ProjectA with a PackageReference, and ProjectB referencing ProjectA, I want to make sure that when ProjectB builds, the .dll inherited transitively from ProjectA doesn't get copied to output (but I want it to get copied for ProjectA, and they have different output directories).

There needs to be a way to control this.

CLI-SDK Icebox PackageReference Feature

Most helpful comment

I've found that you can manually control which .dlls to reference and which .dlls to copy to output from a NuGet package if you turn off all assets on the PackageReference:

<PackageReference Include="Foo.MyPackage" Version="1.0.0" ExcludeAssets="all" GeneratePathProperty="true" />

and then manually reference the .dlls you need:

<Reference Include="$(PkgFoo_MyPackage)\lib\net45\CopyThis.dll">
  <Private>true</Private>
</Reference>
<Reference Include="$(PkgFoo_MyPackage)\lib\net45\DontCopyThis.dll">
  <Private>false</Private>
</Reference>
<None Include="$(PkgFoo_MyPackage)\lib\net45\CopyThisButDontReference.dll">
  <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

Note the usage of GeneratePathProperty on the PackageReference to generate the Pkg*** property, where the package name is prefixed with Pkg and dots replaced with underscores.

All 12 comments

@nkolev92 can you please take a look at this?

@KirillOsenkov
If I understand your scenario correctly
<PrivateAssets>all</PrivateAssets> should do it.

https://docs.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#controlling-dependency-assets

Not quite.

In non-SDK-style projects, set the <CopyNuGetImplementations>false</CopyNuGetImplementations> to not copy the binaries from the referenced packages to output. This also applies to transitively "inherited" packages from PackageReference elements in referenced projects.

In SDK-style projects there's a similar property: <CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>

I'm also looking for a way to copy some .dlls to output, but not others. For instance, https://www.nuget.org/packages/Microsoft.VisualStudio.Composition/15.3.38 - I want to copy Microsoft.VisualStudio.Composition.dll to output, but I don't want any of the satellite resource assemblies. I wasn't able to find a way to do that.

Also with PrivateAssets the problem is that I do want a reference to the .dll added to my project, but not copied to output. With CopyNuGetImplementations=false I can just rely on the inherited transitive package references. However to use PrivateAssets I need to duplicate the PackageReferences from ProjectA in ProjectB, which defeats the purpose of transitivity.

ExcludeAssets=runtime does that, but it will apply to every dll in the lib folder

Clear.
Currently we don't have any type of granular control of package assets of the same category.
//cc
@emgarten

Does @rohit21agrawal's proposal help? (excludeassets runtime)

Nope, not quite, see my description above.

Interesting, I think I'm after the opposite (roslyn 22095) where transitive .net DLLs are copied to output, but not included as references (or at least their APIs are not exposed).

Very needed, to deal with not correctly configurated nugget packages. For example, for now Microsoft.Web.WebView2 copies all dll to output in any case:

Microsoft.Web.WebView2.Core.dll
Microsoft.Web.WebView2.WinForms.dll
Microsoft.Web.WebView2.Wpf.dll

But in WinForms we absolutely no need of Microsoft.Web.WebView2.Wpf.dll...
Wood be useful if ExcludeAssets can handle names for input, for example: ExcludeAssets="Native;Microsoft.Web.WebView2.Wpf.dll;Microsoft.Web.WebView2.WinForms.dll"

I've found that you can manually control which .dlls to reference and which .dlls to copy to output from a NuGet package if you turn off all assets on the PackageReference:

<PackageReference Include="Foo.MyPackage" Version="1.0.0" ExcludeAssets="all" GeneratePathProperty="true" />

and then manually reference the .dlls you need:

<Reference Include="$(PkgFoo_MyPackage)\lib\net45\CopyThis.dll">
  <Private>true</Private>
</Reference>
<Reference Include="$(PkgFoo_MyPackage)\lib\net45\DontCopyThis.dll">
  <Private>false</Private>
</Reference>
<None Include="$(PkgFoo_MyPackage)\lib\net45\CopyThisButDontReference.dll">
  <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

Note the usage of GeneratePathProperty on the PackageReference to generate the Pkg*** property, where the package name is prefixed with Pkg and dots replaced with underscores.

@KirillOsenkov very cool workaround - thank you! I see here only 3 drawback:

  1. You need to know exactly the version of the framework from the package. E.g. _\lib\ netcoreapp3.0 \CopyThis.dll_. And if it will changed - all stop work :(
  2. xml docs will be copied to Release dir too.
  3. I think individual exclude will be more helpful than individual include overall.
Was this page helpful?
0 / 5 - 0 ratings