-
Notifications
You must be signed in to change notification settings - Fork 527
Description
paket update --redirect
generates incorrect System.Collections.Immutable binding redirect (9.0.0.0 instead of 9.0.2.0) with .NET Core-only transitive dependency
Problem Description
When using paket update --redirect
in a mixed .NET Framework / .NET Standard solution, Paket sometimes generates an incorrect app.config
binding redirect for System.Collections.Immutable
. Specifically, despite paket.lock
and project.assets.json
resolving the package version to 9.0.2
, the newVersion
in app.config
is set to 9.0.0.0
instead of 9.0.2.0
for certain .NET Framework 4.8
projects. This leads to a System.IO.FileLoadException
at runtime.
This behavior is specifically observed when a project transitively depends on a NuGet package that is .NET Core-only (e.g., targeting netstandard2.0
and net6.0
but not .NET Framework
). In our case, this problematic dependency is part of the Roslyn compiler.
Expected Behavior
For a .NET Framework 4.8
project, paket update --redirect
should generate a binding redirect for System.Collections.Immutable
(package version 9.0.2
) with newVersion="9.0.2.0"
, as this corresponds to the net462
asset of the package, which is compatible and preferred for .NET Framework 4.8
.
Actual Behavior
For some .NET Framework 4.8
projects in the solution, paket update --redirect
generates:
<dependentAssembly>
<assemblyIdentity name="System.Collections.Immutable"
publicKeyToken="b03f5f7f11d50a3a"
culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-65535.65535.65535.65535" newVersion="9.0.0.0" />
</dependentAssembly>
This causes a System.IO.FileLoadException
at runtime:
System.IO.FileLoadException : Could not load file or assembly 'System.Collections.Immutable, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
Steps to Reproduce (Conceptual)
-
Set up a solution with a mix of .NET Framework 4.8 and netstandard2.0 projects. Your setup includes:
- An app project (executable, .NET 4.8)
- A DLL output project (also .NET 4.8) in the same solution
- An internal NuGet DLL (targets netstandard2.0 and net4.8)
- This internal NuGet DLL uses a Roslyn compiler dependency
- System.Collections.Immutable is used by some DLL output projects in your original solution as well
-
Ensure
System.Collections.Immutable
(e.g., version 9.0.2) is a dependency -
Ensure the Roslyn compiler dependency is the version that is .NET Core-only (e.g., targeting netstandard2.0 and net6.0 but not .NET Framework)
-
Run
paket update --redirect
for the solution -
Observe that .NET Framework 4.8 projects that depend on the path involving the .NET Core-only Roslyn dependency receive the
newVersion="9.0.0.0"
binding redirect for System.Collections.Immutable
Environment
- Paket Version: 9.0.2+a9b12aaeb8d8d5e47a415a3442b7920ed04e98e0
- .NET Framework Version: 4.8
- Other relevant package: System.Collections.Immutable (package version 9.0.2)
- Problematic Transitive Dependency Type: A NuGet package (part of Roslyn compiler) targeting netstandard2.0 and net6.0 but not .NET Framework
Hypothesis of the Cause
It appears that Paket's asset selection logic for binding redirects, when encountering a transitive dependency that only targets netstandard2.0 (or newer, without .NET Framework), might incorrectly prioritize or default to the netstandard2.0 asset of System.Collections.Immutable
(which has assembly version 9.0.0.0) even for .NET Framework 4.8 projects. This happens despite the net462 asset (assembly version 9.0.2.0) being available within the same 9.0.2 package and being more directly compatible with the .NET Framework 4.8 target.
Workaround
Manually overriding the newVersion
in the affected app.config
files to 9.0.2.0
resolves the runtime FileLoadException. Example:
<dependentAssembly>
<assemblyIdentity name="System.Collections.Immutable"
publicKeyToken="b03f5f7f11d50a3a"
culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-65535.65535.65535.65535" newVersion="9.0.2.0" />
</dependentAssembly>