Searching for the best way to dynamically load and unload assemblies in .NET Framework
So I'm working in a codebase that is somewhat mixed right now between .NET 8 (or higher) and .NET Framework 4.7.2. I'm interested in loading a DLL, executing code from that DLL, and then unloading it.
In newer .NETs, assembly load context works remarkably. I can load an assembly, invoke a function from it, and then immediately unload the context which will wait for everything inside of it to eventually stop running (spawned threads, longer-lived objects, etc.) and get GC'd after some time when all of the references die.
However, it appears the way to do this is through AppDomains in .NET Framework. This involves creating a remote object in the main domain, invoking whatever I want to run inside of the new domain from that object, and then unloading the domain. The problem is that unloading the new domain will force all existing threads running in that domain to abort, which is not all that handy if I want to dynamically load code that could potentially spawn threads that run for some time. Is there perhaps some way to track what's all running in an AppDomain and only unload it once everything is said and done?
8 Replies
The overall goal is to compile an assembly, send it through something like a TCP socket (with authentication because I don't want to create an RCE :p) and run code on a host environment. In essence, a live scripting environment
I realize I could use roslyn/csharpanalysis to dynamically compile code on the host from plaintext sent over the network, but the fact that I have to juggle a couple .NET versions means that - to my understanding - the available language versions (i.e. C# 12) aren't available for .NET 4.7.2 like they would be in a normal IDE
You can use the latest language versions even on .netstardard 2.0. You just won't have the runtime features and the newer API's.
Unknown User•4mo ago
Message Not Public
Sign In & Join Server To View
The Roslyn libraries compatible with .NET 4.7.2 allow language versions higher than 8?
I would ideally like to be able to write on version 12, but compile it on 4.7.2
Would this not require that any code I write be tooled specifically to interact with this RPC? I'm looking for something I wouldn't need to hard code for. For instance, you can get the currently running world of the game by doing
Engine.Current.WorldManager.FocusedWorld
. I'd like to be able to do this transparently without needing to explicitly pipe Engine, or the world manager, or the world into the module. I'd have to do that for every little thing I'd wanna access if I'm not mistaken. I'd like to be able to just have a Run()
function that gets poked and have the code be written normally
I'd also be curious if there is any inherent memory leak from running scripts like this, ignoring that the script's code itself could introduce one for a secSet the language version to whatever you want in the project file
It doesn't dictate the target framework
These things are orthogonal
It compiles to the same byte code
No no, I'm not using a project file - this is for compiling scripts at runtime and executing them
Like I want to be able to write a short C# script and then execute it while the program is already running
All the while avoiding memory leaks from repeatedly reloading assemblies into memory
Currently I see two paths:
- Load an already-compiled assembly into memory - this is easy in .NET 8 but not easy in .NET 4.7.2. Namely because AppDomains require tooling to communicate, and also forcefully abort code running inside of them which is very unhealthy
- Compile a C# script at runtime with roslyn. Ideally I'd like to be able to just code a normal C# project and load it at runtime, but roslyn is only really usable to me if I can write in C# 12 on .NET Framework 4.7.2
if you're compiling a dll, you can use a project file
But you can write in C# 12 on .net framework
Roslyn probably isn't for .net framework
It's for .net
Unknown User•4mo ago
Message Not Public
Sign In & Join Server To View