DependencyMagic 0.1.0
dotnet add package DependencyMagic --version 0.1.0
NuGet\Install-Package DependencyMagic -Version 0.1.0
<PackageReference Include="DependencyMagic" Version="0.1.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="DependencyMagic" Version="0.1.0" />
<PackageReference Include="DependencyMagic"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add DependencyMagic --version 0.1.0
#r "nuget: DependencyMagic, 0.1.0"
#:package DependencyMagic@0.1.0
#addin nuget:?package=DependencyMagic&version=0.1.0
#tool nuget:?package=DependencyMagic&version=0.1.0
Dependency Magic
Dependency Magic embeds a consuming project's dependencies as resources in its DLL. It was developed to facilitate consuming NuGet packages in incremental source generators. It may also be useful for distributing single-file executables, although .NET Core can do that on its own now.
How To Use It
Consumers must use C# 9 or higher. Then just add a NuGet dependency on Dependency Magic.
How It Works
Dependency Magic is a source-only NuGet package. If you're building it from source you can't consume it as a DLL or project reference. You have to pack it and install it in a local NuGet feed.
There are only four moving parts:
- A build target that embeds direct and transitive dependencies in the consumer's DLL.
- A handler for
AppDomain.AssemblyResolvethat registers itself via a[ModuleInitializer]. - A polyfill implementation of
ModuleInitializerAttribute. - A properties file that hides all these things in your IDE.
The C# types are compiled as part of the consuming project. This resolves the circular problem of a source generator resolving a dependency on a Dependency Magic DLL. It also makes it much simpler for the assembly resolver to identify the assembly containing the embedded resources.
Caveats
If you're publishing an incremental source generator you should probably only use Dependency Magic during development.
As I understand it, all ISGs contributing to a build run in the same AppDomain. Therefore, if two ISGs depend on
different versions of the same assembly, only one version of the assembly can be loaded and chaos may ensue.
Dependency Magic can't help with that. It just makes it easy for ISGs to consume dependencies when there are no
conflicts. Of course, you never know what other ISGs the consumer of your ISG might be using. So unless and until
MS allows us to run each ISG in its own AppDomain, the general solution is to inline all dependencies as
source. (Or go back to the old console app source generators, which ran in their own process and performed just fine.)
Why do all these System libraries get embedded?
We don't need to embed transitive dependencies that are available in the runtime. But MSBuild doesn't know what runtime
environment a .NET Standard library might run in, and there are a few System and Microsoft packages that are
available in the .NET Core runtime but not in .NET Framework or vice versa.
Ugly Details
When MSBuild resolves dependencies it puts their metadata in an item list called @(ReferencePath). The metadata is
slightly different depending on the target framework. For netstandard2.0, the NuGetPackageId of framework libraries
is NETStandard.Library. For net8.0, it's Microsoft.NETCore.App.Ref. And for net48, framework libraries are
identified by FrameworkFile='true'.
If the CopyLocalLockFileAssemblies property is true, MSBuild creates another item list called
@(ReferenceCopyLocalPaths). This loses the aforementioned framework metadata, but I think MSBuild filters the copy
local assemblies in a similar way. All I can say for sure is that when targeting netstandard2.0 with some arbitrary
NuGet dependencies, exactly the same transitive dependencies that came from NETStandard.Library were excluded from
@(ReferenceCopyLocalPaths). I didn't compare other frameworks.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
This package has no dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0 | 486 | 8/27/2025 |