extensions-hosting
Configure, compose, troubleshoot, and migrate CP.Extensions.Hosting packages for Generic Host applications. Use for WPF, WinForms, WinUI, Avalonia, MAUI, ReactiveUI/Splat, single-instance enforcement, plug-ins, Windows service hosting, normal versus .Reactive package selection, and V3.1.26-to-V4.0.0 upgrades.
来源信息
- 仓库
- reactivemarbles/Extensions.Hosting
- 最近来源活动
- 2026年10月8日 00:54
- 检测到的 SKILL.md 语言
- 英语
- 星标
- 17
- 分支
- 3
安装方式
默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。
检查来源文件
决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。
正在显示 SKILL.md
SKILL.md
来源说明 · 只读预览- name
- extensions-hosting
- description
- Configure, compose, troubleshoot, and migrate CP.Extensions.Hosting packages for Generic Host applications. Use for WPF, WinForms, WinUI, Avalonia, MAUI, ReactiveUI/Splat, single-instance enforcement, plug-ins, Windows service hosting, normal versus .Reactive package selection, and V3.1.26-to-V4.0.0 upgrades.
# Extensions.Hosting
Use this skill when a project references a `CP.Extensions.Hosting.*` package or needs a
Microsoft Generic Host around a desktop UI, plug-in system, or Windows service.
Read the package-root `README.md` before changing code. It contains the complete API
tables, platform recipes, exceptions, and migration guide. Treat the installed package
version and the project's target framework as authoritative.
## Select packages
Choose one platform host when the application owns a UI:
| Application | Host package | Optional ReactiveUI/Splat bridge |
| --- | --- | --- |
| WPF | `CP.Extensions.Hosting.Wpf` | `CP.Extensions.Hosting.ReactiveUI.Wpf` |
| WinForms | `CP.Extensions.Hosting.WinForms` | `CP.Extensions.Hosting.ReactiveUI.WinForms` |
| WinUI | `CP.Extensions.Hosting.WinUI` | `CP.Extensions.Hosting.ReactiveUI.WinUI` |
| Avalonia | `CP.Extensions.Hosting.Avalonia` | `CP.Extensions.Hosting.ReactiveUI.Avalonia` |
| MAUI | `CP.Extensions.Hosting.Maui` | `CP.Extensions.Hosting.ReactiveUI.Maui` |
Add supporting packages only for features that are used:
- `CP.Extensions.Hosting.SingleInstance` for mutex-backed single-instance enforcement.
- `CP.Extensions.Hosting.Plugins` for plug-in discovery and hosted-service plug-ins.
- `CP.Extensions.Hosting.PluginService` for console or Windows service plug-in hosts.
- `CP.Extensions.Hosting.Identity.EntityFrameworkCore.SqlServer` or `.Sqlite` for
database and Identity registration.
Do not reference `CP.Extensions.Hosting.MainUIThread` directly unless implementing a
new platform adapter.
## Choose the normal or `.Reactive` family
Use normal packages with the normal ReactiveUI and ReactiveUI.Primitives family.
Select the `.Reactive` variant for plug-in, PluginService, or ReactiveUI bridge
features when that project and its plug-ins use the
`ReactiveUI.Primitives.*.Reactive` or `ReactiveUI.*.Reactive` dependency family. A UI
bridge is not required for `Plugins.Reactive` or `PluginService.Reactive`.
| Normal | `.Reactive` |
| --- | --- |
| `CP.Extensions.Hosting.Plugins` | `CP.Extensions.Hosting.Plugins.Reactive` |
| `CP.Extensions.Hosting.PluginService` | `CP.Extensions.Hosting.PluginService.Reactive` |
| `CP.Extensions.Hosting.ReactiveUI.<Platform>` | `CP.Extensions.Hosting.ReactiveUI.<Platform>.Reactive` |
| `ReactiveMarbles.Extensions.Hosting.Plugins` | `ReactiveMarbles.Extensions.Hosting.Reactive.Plugins` |
| `ReactiveMarbles.Extensions.Hosting.PluginService` | `ReactiveMarbles.Extensions.Hosting.Reactive.PluginService` |
| `ReactiveMarbles.Extensions.Hosting.ReactiveUI` | `ReactiveMarbles.Extensions.Hosting.Reactive.ReactiveUI` |
Platform hosts (`CP.Extensions.Hosting.Wpf`, `.WinForms`, `.WinUI`, `.Avalonia`,
`.Maui`), `CP.Extensions.Hosting.SingleInstance`,
`CP.Extensions.Hosting.MainUIThread`, Identity helpers, and Log4Net have no
`.Reactive` siblings. Keep those normal packages even when using a `.Reactive` bridge
or plug-in package. For example, `CP.Extensions.Hosting.ReactiveUI.Wpf.Reactive` still
uses `CP.Extensions.Hosting.Wpf`.
Never mix normal and `.Reactive` variants of the same feature in one project.
Do not add direct Rx.NET references merely to use these hosting APIs.
## Compose the host
Apply configuration before the matching lifetime method, then build once:
```csharp
using Microsoft.Extensions.Hosting;
using ReactiveMarbles.Extensions.Hosting.AppServices;
using ReactiveMarbles.Extensions.Hosting.ReactiveUI;
using ReactiveMarbles.Extensions.Hosting.Wpf;
var builder = Host.CreateApplicationBuilder(args);
builder.ConfigureSingleInstance("Contoso.Desktop");
builder.ConfigureSplatForMicrosoftDependencyResolver();
builder.ConfigureWpf(wpf => wpf
.UseApplication(typeof(App))
.UseWindow(typeof(MainWindow)));
builder.UseWpfLifetime();
using var host = builder.Build();
host.MapSplatLocator(_ => { });
await host.RunAsync().ConfigureAwait(false);
```
Ordering rules:
1. Register application services and optional Splat integration.
2. Configure single-instance enforcement before platform-hosted services when used.
3. Call `ConfigureWpf`, `ConfigureWinForms`, `ConfigureWinUI`, `ConfigureAvalonia`, or
`ConfigureMaui`.
4. Call the matching `Use*Lifetime` method where the platform exposes one.
5. Build the host.
6. Call `MapSplatLocator` only on the built host.
7. Run and dispose the host.
`UseWpfLifetime` and `UseAvaloniaLifetime` throw when called before their matching
`Configure*` method. WinUI installs its hosted lifetime in `ConfigureWinUI`; it has no
`UseWinUILifetime` method.
## Initialize services on the UI thread
Register platform initialization services with DI. The host invokes them on the
platform UI thread:
```csharp
public sealed class ThemeInitializer : IWpfService
{
public void Initialize(System.Windows.Application application)
{
application.Resources["AccentBrush"] =
new System.Windows.Media.SolidColorBrush(
System.Windows.Media.Colors.CornflowerBlue);
}
}
builder.Services.AddSingleton<IWpfService, ThemeInitializer>();
```
Equivalent contracts are `IWinFormsService`, `IWinUIService`, `IAvaloniaService`, and
`IMauiService`.
## ReactiveUI schedulers
Call the platform `ConfigureSplatForMicrosoftDependencyResolver()` extension. For WPF,
V4 automatically binds `RxSchedulers.MainThreadScheduler` to the dispatcher owned by
the hosted application through an internal `IWpfService`.
Do not add or register `SchedulerRegistrar`. Do not use removed `RxApp` scheduler
workarounds.
## Plug-ins
Configure scan roots and explicit include patterns:
```csharp
builder.ConfigurePlugins(plugins =>
{
plugins?.AddScanDirectories(AppContext.BaseDirectory);
plugins?.IncludePlugins("plugins/**/*.Plugin.dll");
plugins?.ExcludePlugins("plugins/**/*.Disabled.dll");
plugins?.RequirePlugins();
});
```
Implement `IPlugin.ConfigureHost` to register services. Use `PluginOrderAttribute` for
deterministic order and `HostedServiceBase<T>` only when its application-lifetime
callbacks fit the service. `OnStarted()` runs once; implement bounded retry and
cancellation explicitly when needed.
## Single-instance applications
Use `ConfigureSingleInstance` for hosted applications:
```csharp
builder.ConfigureSingleInstance(mutex =>
{
mutex.MutexId = "Contoso.Desktop";
mutex.IsGlobal = false;
mutex.WhenNotFirstInstance = (_, logger) =>
logger.LogWarning("Another instance is already running.");
});
```
Use one of the four explicit `ResourceMutex.Create` overloads for direct locking. A
blank mutex id is invalid. Dispose the mutex on its owning thread.
## Diagnose lifecycle failures
- Missing UI: verify the application/window/page type is registered and the shell
implements the platform shell interface.
- Host never exits: enable the platform lifetime after platform configuration.
- WPF/Avalonia lifetime throws during setup: reverse the `Use*Lifetime` and
`Configure*` calls.
- MAUI/WinUI shutdown throws: the running application must expose a usable dispatcher;
rejected dispatch is an `InvalidOperationException`, and cancellation is honored.
- Avalonia fails on Windows startup: enter the hosted UI from an STA thread.
- Splat cannot resolve host services: call `MapSplatLocator` after `Build`.
- No plug-ins load: verify scan roots, glob patterns, runtime subdirectory, and
`ValidatePlugin`.
## Migrate V3.1.26 to V4.0.0
1. Upgrade every `CP.Extensions.Hosting.*` reference together.
2. Rebuild all consumers; V4 changes binary signatures even where source calls remain.
3. Choose the normal or `.Reactive` family and update namespaces as a unit.
4. Replace `System.Reactive.ICancelable` assumptions on `HostedServiceBase<T>` with
`ReactiveUI.Primitives.Disposables.IsDisposed` and `IDisposable`.
5. Replace optional `ResourceMutex.Create` assumptions with an explicit overload.
6. Replace partial `ServiceHost.Create`/`CreateApplication` calls with either the
two-argument overload or all six arguments.
7. Make custom WPF, Avalonia, WinForms, and MAUI shells implement their new platform
base interface.
8. Remove `SchedulerRegistrar`; use hosted WPF scheduler wiring.
9. Retarget MAUI platform-workload applications, and all `ReactiveUI.Maui`
consumers, to net10 or later. The base `CP.Extensions.Hosting.Maui` host still
supports net9; its platform workload assets begin at net10. Move Log4Net
`netstandard2.0` consumers to a supported target.
10. Run a warning-as-error build and exercise startup and shutdown on the native UI.
## Validate
For a consumer project, restore, build, and test the application for every target
platform/runtime, then manually exercise native startup and shutdown.
For a repository checkout:
```powershell
cd src
dotnet workload restore
dotnet restore Extensions.Hosting.slnx
dotnet build Extensions.Hosting.slnx -c Release -warnaserror
dotnet test --solution Extensions.Hosting.slnx -c Release
```
For consumer projects, validate both the target platform and deployment runtime.
MAUI, WinUI, WPF, WinForms, and Windows service behavior cannot be fully established
by a platform-neutral unit test alone.
在 GitHub 查看