I'll start off saying that this doesn't sound like a good idea. You didn't explain the scenario about why you want to do this, so we have no way of suggesting better approaches. If it's a web application that you don't want to have downtime for, a better approach might be to have a load balancer and when you release a new version of your web app, to configure the load balancer to send all new requests to the new contains/version while the existing connections on the old version drain.
If your app is a queue listener, you don't need hot-loading at all. Just have an app which creates a pull request on your source code to update nuget package version numbers when they're available, have the CI automatically build the change and if tests pass you can automate approving/merging the PR then your CD can automatically deploy and decommission the previous version. This would be less risky than automatically loading new versions since you risk the new version having bugs or not being binary compatible and now your app is going to crash.
Anyway, if you really do have a good reason to hot-reload assemblies, on .NET Core you'll need to use AssemblyLoadContext
. However, it's such an unusual case to need this, that I can't find any realistic examples on how to use it. All the "examples" I've seen use AssemblyLoadContext.Default
which I assume is equivilent to using a single context and therefore won't let you load different versions of the same assembly. So, if you want to go down this path, you're probably going to have to figure it out yourself. Lots of trial and error, debugging and possibly reading the coreclr source code. As some commenters to your question mentioned, you'll also need to handle the case that an assembly was compiled against one version of a dependency, but you're now going to load a different version. In the .NET Framework is uses something called Assembly Binding Redirect. The way most people use this is with an app.config or web.config file, but that won't work for you since it will change at runtime. I'm sure there's an API to deal with it programatically, which you'll also need to figure out. I'm not sure how/if binding redirects are different in .NET Core compared to the .NET Framework, so that's yet another thing you'll need to figure out, but I'm sure a couple of good searches on google will give you an answer to that.
Once you get assembly hot reloading working, you can either read the NuGet server API and implement your own client, or you can use the NuGet client SDK. But the NuGet Client team's primary focus are the tools (Visual Studio integration, dotnet cli, nuget.exe), they just publish the packages for convenience (plus as a way to share the libraries with dotnet cli and mono), so there are no docs on using the SDK. Also note that while the NuGet client team tries not to break the packages binary API, it's a secondary concern when needing to implement features and bug fixes for the tools. The NuGet client SDK track Visual Studio version number, it doesn't use semantic versioning, so when you try to update to newer NuGet client packages, you might find you need to change your code when you otherwise might not expect. It's pretty rare, but I generally recommend the "ports and adapters" pattern, and this is an excellent example of when it's particularly useful. At least with the NuGet client packages, there are blog posts from people who figured it out and shared how they did whatever they needed. Otherwise since NuGet itself is opensource, you can look though NuGet's code to see how it uses the packages internally, and use that as a guide to help you figure out what you want to do. If you go down this path you'll need to do most of what the nuget tools do:
- Query a NuGet feed to find what versions of a package are available, then choose which version you want to use and check if that version is already downloaded.
- Download and extract the package.
- Asset selection. Particularly when a package has libraries for multiple TFMs, you need to know which one to use based on your project's TFM
- The NuGet client at this stage would either write the
project.assets.json
file, used by the .NET SDK, or edit the packages.config and csproj files, depending if the project uses PackageReference
or packages.config
. In your case this is where you integrate with assembly hot-reload.
Note that in the general case, the process above, or depending on how you implement it a single step, could be recursive because a package can have dependencies. So, the dependencies also need to be retrieved, but a package can have different dependencies depending on which TFM is selected, so you need to figure out do you want to download all dependencies, even ones that will never be used after asset selection, or do you want to do asset selection first to minimise the packages that you download. Also when multiple packages have a dependency on different versions of a single package, you need to make a decision about which version of the package you want to use.
So, that's the high level algorithm you'll need to implement. As I mentioned, most of this doesn't have API docs with examples on exactly how to implement it, and very few, if any, examples exist on the internet. Like I wrote in the first paragraph, I don't think this is a good idea. It's probably easier to automate your CI/CD pipelines, and if necessary automate changes to a load balancer's configuration, rather than making such a complex app. Sometimes orchestrating a bunch of simple apps is easier than making a complex app.