In a previous post I showed how to build for
net4x on macOS, and it turns out you have everything you need to do it with the .NET Core SDK, except for the Reference Assemblies, and in that post I showed some workarounds.
This problem doesn't just exist on macOS however, it's also applicable when you are building on Linux, in Docker, or even on Windows without having the right targeting pack installed.
Now the dotnet team have made a more seamless way of doing this, with a new NuGet metapackage; Microsoft.NETFramework.ReferenceAssemblies.
How do I use it?
Just add this to your project file:
The team are talking about adding this to the SDK imports, so in future it may just already be imported and "just work".
PrivateAssets part is to make sure it doesn't appear as a dependency of your project.
What's a metapackage?
It's a package that contains no payload, just depends on a number of other packages, as a convenient way to add a group of packages. You can read more here.
Here is what the metapackage dependencies look like:
... and so on.
I don't want to download all TFMs
As you can see from the screenshot above, the metapackage references all the .NET Framework TFMs (Target Framework Moniker), you wouldn't want to download all of these at build time when you only need one.
Well there's no need to worry, when you do a NuGet restore, dependencies are resolved per framework. So let's say we had this in our project file:
If we do a NuGet restore, we can look at the contents of
/obj/project.asset.json and we will see:
Notice how it's only resolved
Microsoft.NETFramework.ReferenceAssemblies.net461 as a dependency, and not all of the others.
How does it work?
If we unzip the
net461 package and open it up, it looks like this:
build/.NETFramework/v4.6.1 folder contains the reference assemblies, and the
Microsoft.NETFramework.ReferenceAssemblies.net461.targets file looks like this:
Notice that the top level condition means that this package will do nothing when you are not building for
net461 (this is evaluated per-tfm for multi-targeting).
EnableFrameworkPathOverride is set to
false, so the
FrameworkPathOverride we used in the previous post can be removed as it will be ignored anyway, and instead it sets the
TargetFrameworkRootPath, which is how it will find the assemblies shipped in the package.
As you can see from the version, this package is still in preview, but I can confirm it works great and you can take out those old workarounds and custom NuGet feed. This is excellent work from the dotnet team!