NGS.ModuleHost 1.0.1

dotnet add package NGS.ModuleHost --version 1.0.1
                    
NuGet\Install-Package NGS.ModuleHost -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NGS.ModuleHost" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NGS.ModuleHost" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="NGS.ModuleHost" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NGS.ModuleHost --version 1.0.1
                    
#r "nuget: NGS.ModuleHost, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NGS.ModuleHost@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NGS.ModuleHost&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=NGS.ModuleHost&version=1.0.1
                    
Install as a Cake Tool

Read in other languages: Русский

NGS.ModuleHost

A pluggable module host for .NET with provable unloading. Load, unload and hot-reload code at runtime without restarting the process — with a guarantee that a module's assembly actually leaves memory after unload.

NuGet License .NET

What it is

A module is a plain .NET assembly in its own folder. The host loads it into a dedicated collectible AssemblyLoadContext, gives it an isolated DI container, and starts it. When a module's ALC is unloaded, it is provably collected by the GC: if any live reference to the module's code remains in the host, UnloadAsync does not pretend everything is fine — it throws ModuleLeakException. That verified guarantee is what sets this apart from plugin loaders that "sort of" unload.

  • Target framework: net10.0
  • Single dependency: Microsoft.Extensions.DependencyInjection
  • Host and modules communicate through DI

Who needs it

Any application with a plugin architecture. Hot-reload is an option, not an obligation:

  • Hot-reload — load, unload and reload modules at runtime without a restart. For long-running processes where restarting is expensive: bots, game servers, assistants, SaaS with plugins.
  • Load-only — load modules at startup and never unload them; updating means restarting the process. Modularity and extensibility without the unload discipline. Great for ASP.NET and any app that can simply restart.

If you never call UnloadAsync/ReloadAsync, you don't pay for unloading (no GC probes, no StopAsync discipline).

Important: ALC isolation is an unload boundary, not a sandbox. Untrusted code is not isolated this way inside a single process.

Installation

dotnet add package NGS.ModuleHost

Quick start

The host lives in your DI container:

using Microsoft.Extensions.DependencyInjection;
using NGS.ModuleHost;

var services = new ServiceCollection()
    .AddModuleEvents()   // optional subsystems: event bus, cache, configs, tasks, shared services
    .AddModuleCache()
    .AddModuleTasks()
    .AddModuleHost()
    .BuildServiceProvider();

var host = services.GetRequiredService<ModuleHost>();

await host.LoadAllAsync("modules");     // load everything from ./modules
await host.ReloadAsync("acme.hello");   // swap the .dll without restarting the process
await host.UnloadAsync("acme.hello");   // unload — with a GC-verified collection check

And a module is a single class:

using Microsoft.Extensions.DependencyInjection;
using NGS.ModuleHost;
using NGS.ModuleHost.Events;

public sealed class HelloModule : IModule
{
    public string Id => "acme.hello";

    public Task StartAsync(IServiceProvider services, CancellationToken ct)
    {
        var bus = services.GetRequiredService<IEventBus>();
        bus.Subscribe<Ping>((e, _) => { /* ... */ return Task.CompletedTask; });
        return Task.CompletedTask;
    }
}

The one unload rule

Built-in subsystems (events, cache, [Loop] tasks, shared services) release everything module-owned themselves on unload — you don't unsubscribe manually. Manual cleanup is needed only for "raw" roots the module created itself: its own Timer, Task, or a subscription to a C# event on an external object. Release those in StopAsync — otherwise the ALC won't unload and UnloadAsync will honestly say so.

More detail — in Docs.md.

Demo

A WPF app: on the left, a list of modules with load / unload / reload buttons; on the right, a panel where modules add their UI on the fly and remove it on unload.

dotnet run --project sample/NGS.ModuleHost.Sample

The demo widgets show both approaches to module UI: Clock builds a WPF control itself (direct WPF), while Counter describes its UI as data and the host renders it (declarative). Both unload cleanly.

On WPF and unloading. The library itself is framework-agnostic. WPF has one caveat: text input controls (TextBox/RichTextBox) initialize the system Text Services (TSF) subsystem, which holds the native part of the last text module until the next text input — so UnloadAsync of such a module may report a leak (the managed part is unloaded, and there is no accumulation). This is a WPF limitation, not the library's; details in Docs.md.

Features

  • Isolation and unloading — a dedicated ALC and child-DI per module, provable collection after unload
  • Reload — swap a .dll without restarting the process
  • Manifest — id, version, dependencies; dependency-ordered loading
  • Subsystems (all optional): event bus, shared cache, JSON configs, inter-module services, background [Loop] tasks
  • Extension point — your own subsystems via IModuleHostFeature

Documentation

The full guide is in Docs.md: API, module layout and build, contract assembly, manifest, every subsystem with examples, leak diagnostics.

License

Apache-2.0 © 2026 ZikQ

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
1.0.1 110 7/13/2026
1.0.0 115 7/13/2026