AssemblyShader 1.1.3
dotnet add package AssemblyShader --version 1.1.3
NuGet\Install-Package AssemblyShader -Version 1.1.3
<PackageReference Include="AssemblyShader" Version="1.1.3"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add AssemblyShader --version 1.1.3
#r "nuget: AssemblyShader, 1.1.3"
// Install AssemblyShader as a Cake Addin #addin nuget:?package=AssemblyShader&version=1.1.3 // Install AssemblyShader as a Cake Tool #tool nuget:?package=AssemblyShader&version=1.1.3
.NET Assembly Shader
A .NET assembly shader for allowing .NET apps to load multiple versions of the same assembly.
Shading Transitive Dependencies
This package includes build logic to rename assemblies in your dependency graph that would otherwise be unified by the .NET SDK. Consider the following project's dependency graph:
<ItemGroup>
<PackageReference Include="PackageA" Version="1.0.0" />
<PackageReference Include="PackageB" Version="1.0.0" />
</ItemGroup>
When PackageA
and PackageB
are restored, PackageZ
version 2.0.0
will be used since it is the highest resolved version in the dependency graph. At runtime, PackageA
will be forced to use PackageZ
version 2.0.0
even if it was built and tested against PackageZ
version 1.0.0
. If there have been any breaking runtime changes in PackageZ
, PackageA
could fail at runtime. Since only one version of PackageZ
can exist in the application
directory, it can be difficult to workaround the issue.
On .NET Framework, you can place PackageZ.dll
version 1.0.0.0
into a subfolder of the application directory and use assembly binding information in the App.config
to tell the runtime where to find it. This will only work
if the assembly is strong name signed however, since the .NET assembly loader can only load different versions of the same assembly side-by-side if they are strong named signed.
On .NET Core, there is no way to work around this issue. The .NET assembly loader will always load the highest version of an assembly. The only path forward is to recompile PackageA
against PackageZ
version 2.0.0.0
which is not always possible.
Assembly shading provides an escape hatch for the above example. It renames the PackageZ
version 1.0.0
assembly so it can exist in the same directory as PackageZ
version 2.0.0
and updates any assemblies that reference it.
<ItemGroup>
<PackageReference Include="AssemblyShader" Version="1.0.0" PrivateAssets="All" />
<PackageReference Include="PackageA" Version="1.0.0" ShadeDependencies="PackageZ" />
<PackageReference Include="PackageB" Version="1.0.0" />
</ItemGroup>
As the project is built, the package shader logic finds the assemblies in PackageZ
version 1.0.0
and renames them. The renamed assembly is then copied to the application output directory.
Now the output folder has both PackageZ.dll
which is version 2.0.0.0
and PackageZ.1.0.0.0.dll
.
PackageA.dll
was also updated to reference PackageZ.1.0.0.0.dll
instead of PackageZ.dll
.
Shading Entire Packages
If you wish to shade all of the assemblies in a particular package and its transitive dependencies, you can use the Shade
property:
<ItemGroup>
<PackageReference Include="Newtonsoft.Json.Bson" Version="1.0.2" Shade="true" />
</ItemGroup>
Shading Assemblies Eclipsed by Explicit Package References
When you have specified a newer version of a transitive dependency in your project, NuGet will eclipse this transitive version and as a performance optimization not download it. This means that the assemblies won't be available in the global packages folder to shade. To workaround this issue, the assembly shader will log an error indicating that you need to tell NuGet to download the dependency with a <PackageDownload />
item.
In the below example since PackageZ
version 2.0.0
is declared explicitly, the transitive dependency of PackageA
on PackageZ
version 1.0.0
will be eclipsed and not made available for shading.
<ItemGroup>
<PackageReference Include="AssemblyShader" Version="1.0.0" PrivateAssets="All" />
<PackageReference Include="PackageA" Version="1.0.0" ShadeDependencies="PackageZ" />
<PackageReference Include="PackageB" Version="1.0.0" />
<PackageReference Include="PackageZ" Version="2.0.0" />
</ItemGroup>
You will need to specify a <PackageDownload />
item to indicate to NuGet to still make it available:
<ItemGroup>
<PackageReference Include="AssemblyShader" Version="1.0.0" PrivateAssets="All" />
<PackageReference Include="PackageA" Version="1.0.0" ShadeDependencies="PackageZ" />
<PackageReference Include="PackageB" Version="1.0.0" />
<PackageReference Include="PackageZ" Version="2.0.0" />
<PackageDownload Include="PackageZ" Version="[1.0.0]" />
</ItemGroup>
Limitations
Assembly shading can be a great way to fix runtime issues with dependencies, but it does have some limitations.
- Shaded assemblies are strong name signed with a new public key pair. In the process, Authenticode signatures are lost.
- Since a shaded assembly is loaded side-by-side with a newer version, you will not be able to pass types around between the two versions. You will get a compile-time error if you attempt to do this. If you have to pass types around between assemblies, shading will not be possible.
- Assembly references will be updated because they are easy to discover but any code that uses reflection to load types will not be updated. This includes
Assembly.Load
andAssembly.LoadFrom
.
If you have code that uses reflection to load types from a shaded assembly, you will need to update it to use the new assembly name.
Learn more about Target Frameworks and .NET Standard.
This package has no dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on AssemblyShader:
Repository | Stars |
---|---|
microsoft/MSBuildSdks
MSBuild project SDKs
|
Version | Downloads | Last updated |
---|---|---|
1.1.3 | 96 | 12/13/2024 |