Skip to main content

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 查看