NGS.ModuleHost
1.0.0
See the version list below for details.
dotnet add package NGS.ModuleHost --version 1.0.0
NuGet\Install-Package NGS.ModuleHost -Version 1.0.0
<PackageReference Include="NGS.ModuleHost" Version="1.0.0" />
<PackageVersion Include="NGS.ModuleHost" Version="1.0.0" />
<PackageReference Include="NGS.ModuleHost" />
paket add NGS.ModuleHost --version 1.0.0
#r "nuget: NGS.ModuleHost, 1.0.0"
#:package NGS.ModuleHost@1.0.0
#addin nuget:?package=NGS.ModuleHost&version=1.0.0
#tool nuget:?package=NGS.ModuleHost&version=1.0.0
NGS.ModuleHost
Хост подключаемых модулей для .NET с доказуемой выгрузкой. Грузите, выгружайте и перезагружайте код в рантайме без перезапуска процесса — и с гарантией, что после выгрузки сборка модуля действительно уходит из памяти.
Что это
Модуль — обычная .NET-сборка в своей папке. Хост грузит её в отдельный collectible
AssemblyLoadContext, даёт изолированный DI-контейнер и запускает. При выгрузке ALC модуля
доказуемо собирается GC: если из хоста осталась хоть одна живая ссылка на код модуля,
UnloadAsync не сделает вид, что всё хорошо, — он бросит ModuleLeakException. Именно эта
проверяемая гарантия и отличает либу от «плагин-лоадеров», которые «вроде выгружают».
- Целевой фреймворк: net10.0
- Единственная зависимость:
Microsoft.Extensions.DependencyInjection - Хост и модули общаются через DI
Кому нужно
Долгоживущим расширяемым процессам, где рестарт дорог или неуместен: боты, игровые серверы, торговые и автоматизационные системы, SaaS с плагинами, — всё, где хочется добавлять, обновлять и убирать функциональность на лету.
Обычному приложению, которому проще перезапуститься, это не нужно. И важно: изоляция ALC — это граница выгрузки, а не sandbox. Недоверенный код в одном процессе так не изолируют.
Установка
dotnet add package NGS.ModuleHost
Быстрый старт
Хост живёт в вашем DI-контейнере:
using Microsoft.Extensions.DependencyInjection;
using NGS.ModuleHost;
var services = new ServiceCollection()
.AddModuleEvents() // опциональные подсистемы: шина, кеш, конфиги, задачи, общие сервисы
.AddModuleCache()
.AddModuleTasks()
.AddModuleHost()
.BuildServiceProvider();
var host = services.GetRequiredService<ModuleHost>();
await host.LoadAllAsync("modules"); // грузим всё из ./modules
await host.ReloadAsync("acme.hello"); // подменяем .dll без рестарта процесса
await host.UnloadAsync("acme.hello"); // выгружаем — с проверкой сборки GC
А сам модуль — один класс:
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;
}
}
Главное правило выгрузки
Встроенные подсистемы (события, кеш, [Loop]-задачи, общие сервисы) снимают всё модульное
сами при выгрузке — отписываться не нужно. Ручная уборка требуется только для «сырых» корней,
которые модуль завёл сам: свой Timer, Task, подписка на C#-событие внешнего объекта. Их
снимайте в StopAsync — иначе ALC не выгрузится, и UnloadAsync честно об этом скажет.
Подробнее — в Docs.md.
Демо
WPF-приложение: слева список модулей с кнопками загрузить / выгрузить / перезагрузить, справа панель, куда модули на лету добавляют свой UI и убирают его при выгрузке.
dotnet run --project sample/NGS.ModuleHost.Sample
Виджеты в демо показывают оба подхода к UI из модуля: Clock сам строит WPF-контрол (прямой WPF), Counter описывает UI данными, а хост его рисует (декларативно). Оба выгружаются чисто.
Про WPF и выгрузку. Библиотека сама по себе framework-agnostic. В WPF есть один нюанс: контролы текстового ввода (
TextBox/RichTextBox) инициализируют системную подсистему Text Services (TSF), которая держит нативную часть последнего текстового модуля до следующего ввода — поэтомуUnloadAsyncтакого модуля может сообщить об утечке (управляемая часть при этом выгружена, накопления нет). Это ограничение WPF, не библиотеки; подробнее — в Docs.md.
Возможности
- Изоляция и выгрузка — свой ALC и child-DI на модуль, доказуемая сборка после unload
- Reload — подмена .dll без перезапуска процесса
- Манифест — id, версия, зависимости; порядок загрузки по зависимостям
- Подсистемы (все опциональны): шина событий, общий кеш, JSON-конфиги, межмодульные сервисы,
фоновые
[Loop]-задачи - Точка расширения — свои подсистемы через
IModuleHostFeature
Документация
Полное руководство — Docs.md: API, раскладка и сборка модуля, контрактная сборка, манифест, каждая подсистема с примерами, диагностика утечек.
Лицензия
Apache-2.0 © 2026 ZikQ
| Product | Versions 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. |
-
net10.0
- Microsoft.Extensions.DependencyInjection (>= 10.0.9)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.