Disable transitive PackageReference dependency for a specific MsBuild project
Asked Answered
H

3

10

I am migrating an old style MsBuild csproj project to using PackageReference format and have run into a problem with transitive dependencies.

Consider the following Project A reference NuGet package B and C, each containing one single assembly using PackageReference. On Build Project A uses IL merge to incorporate B as public symbols in the A assembly and C as internalized symbols. Project D have a project reference to A.

The transitive dependencies case D to reference A, B and C. When building D, compile errors of the type error CS0433: The type 'X' exists in both 'A' and 'B' occur.

Is there any way to force D to not add an explicit reference to B or C in the scenario above?

Hintze answered 6/9, 2018 at 15:27 Comment(0)
H
7

I ended up using a workaround to move the transitive dependency to an alias to get around the compiler error.

<Target Name="ChangeAliasesOfBNameAssemblies" BeforeTargets="FindReferenceAssembliesForReferences;ResolveReferences">
  <ItemGroup>
    <ReferencePath Condition="'%(FileName)' == 'B'">
      <Aliases>nonmerged</Aliases>
    </ReferencePath>
  </ItemGroup>
</Target>

I tried to use private assets but couldn't get the compiler error to go away in that way.

Hintze answered 10/9, 2018 at 7:9 Comment(2)
This worked for me! I didn't realize that aliasing the package I didn't want to use would cause the types from the other one to be usable, so I kept trying to alias the package I did want (which was a problem, because it was Microsoft.NETCore.Platforms...)Blitzkrieg
WOW, impressive. your approach just helped me solve an "ambiguous reference" error. Thank you very much.Deidredeific
T
3

Disable transitive PackageReference dependency for a specific MsBuild project

If I understand you correct, you can try to use property <PrivateAssets>all</PrivateAssets>or PrivateAssets="all" for the PackageReference. If you have a package that's marked with private assets it merely prevents it from flowing to parent project or getting packed.

enter image description here

<PackageReference Include="B" Version="1.0.0" PrivateAssets="all">
<PackageReference Include="C" Version="1.0.0" PrivateAssets="all">

You can check the document Controlling dependency assets and this thread for some details.

Hope this helps.

Tokharian answered 7/9, 2018 at 3:11 Comment(3)
I tried using PrivateAssets in A's reference to B and C, but I still got the conflicting types. I ended up using the workaround here github.com/NuGet/Home/issues/4989#issuecomment-310565840 to put B in a non-used alias.Hintze
@ViktorGriph, Glad to know that you have resolved this issue. Would you please post your workaround as answer, this can be beneficial to other community members reading this thread and easier find the answer :).Tokharian
This doesn't resolve the issue for us. We need a way to ignore transitive dependencies in the PackageReference paradigm similar to the way we could in the packages.config paradigm, by just removing the references that nuget added. PrivateAssets only affects the output directory, it does not affect the dependency graph.Bortz
V
2

I was looking for this too and this answer kept popping up in google searches, but it didn't have the solution I know off (but can never remember), so I'll add my answer for future reference.

PrivateAssets can be used to hide many things, but hiding all is a bad move imo. You want some assets to move transitively, for example, for your app to run after a dotnet publish, you'll need the assemblies you need, at runtime. Hiding all assets means that when publishing, you may miss a few critical things - similar to deleting some files from the output.

From reading MS docs on the subject, I think what I want to hide, in order to not transitively be able to compile up against an assembly (but still have it at runtime), is compile. So I'll set my PrivateAssets to contentfiles;analyzers;build;compile. This should mean that if MyLibraryB depends on NugetPackageA - then MyAppC depending on MyLibraryB will be able to run and publish correctly, without being able to use any classes or code from NugetPackageA.

Note: This of course means that MyLibraryB must not expose any public API that uses types found in NugetPackageA. The consumer won't be able to use those public API's, at least not without themselves also referencing NugetPackageA.

Vday answered 9/7, 2022 at 17:21 Comment(1)
This was our scenario, hiding a 3rd party dependency from having its types appear in our consumers' scope while still being able to use it ourselves. Setting PrivateAssets this way seems to have done the trick.Towrope

© 2022 - 2024 — McMap. All rights reserved.