.NET Generic Host 是一个通用的应该程序构建方式,不只是适用于 asp.net core,可以用在任何 .NET 项目中。
具体支持的 .NET 框架可以看这里 NuGet Gallery | Microsoft.Extensions.Hosting 8.0.1
.NET Generic Host - .NET | Microsoft Learn
本文用于记录使用 .NET Generic Host 来管理 WPF(使用 Stylet)项目所需的修改,逐步更新,仅供参考。
模板代码:JasonGrass/WpfAppTemplate1: WPF + Stylet + Hosting
// csproj <ItemGroup> <PackageReference Include="Stylet" Version="1.3.7" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0-rc.2.24473.5" /> </ItemGroup>
因为要手动使用 Main 函数,不使用默认的 App 的加载,需要将 App.xaml 从 ApplicationDefinition 修改成 Page。
// csproj <ItemGroup> <ApplicationDefinition Remove="App.xaml" /> <Page Include="App.xaml" /> </ItemGroup>
删除 App.xaml 中的 StartUrl,修改成 Stylet 的 ApplicationLoader
// App.xaml<Application x:Class="WpfAppTemplate1.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfAppTemplate1" xmlns:s="https://github.com/canton7/Stylet"> <Application.Resources> <s:ApplicationLoader> <s:ApplicationLoader.Bootstrapper> <local:Bootstrapper /> </s:ApplicationLoader.Bootstrapper> </s:ApplicationLoader> </Application.Resources></Application>
添加 Main 函数,创建 IHostBuilder 并运行,然后运行 App.
在 CreateHostBuilder 中,可以扩展所需的 hosting 相关的服务,如配置,日志等。
public partial class App : Application{ private static IServiceProvider? _serviceProvider;
public static IServiceProvider ServiceProvider { get => _serviceProvider!; private set => _serviceProvider = value; }
[STAThread] static void Main(string[] args) { using IHost host = CreateHostBuilder(args).Build(); ServiceProvider = host.Services; host.StartAsync();
var app = new App(); app.InitializeComponent(); app.Run(); }
public static T? GetService<T>() where T : class { return ServiceProvider.GetService<T>(); }
private static IHostBuilder CreateHostBuilder(string[] args) { var builder = Host.CreateDefaultBuilder(args) .ConfigureServices(serviceCollection => { serviceCollection.AddSingleton(_ => Current.Dispatcher); });
return builder; }}
因为不在使用 Stylet 自带的 IOC 容器,而使用微软的,需要手动添加一个 MicrosoftDependencyInjectionBootstrapper
这里的代码,可以直接从官方给的模板中复制过来.
public class MicrosoftDependencyInjectionBootstrapper<TRootViewModel> : BootstrapperBase where TRootViewModel : class{ private ServiceProvider? _serviceProvider; private TRootViewModel? _rootViewModel;
protected virtual TRootViewModel RootViewModel => this._rootViewModel ??= (TRootViewModel)this.GetInstance(typeof(TRootViewModel));
public IServiceProvider ServiceProvider => this._serviceProvider!;
protected override void ConfigureBootstrapper() { var services = new ServiceCollection(); this.DefaultConfigureIoC(services); this.ConfigureIoC(services); this._serviceProvider = services.BuildServiceProvider(); }
/// <summary> /// Carries out default configuration of the IoC container. Override if you don't want to do this /// </summary> protected virtual void DefaultConfigureIoC(IServiceCollection services) { var viewManagerConfig = new ViewManagerConfig() { ViewFactory = this.GetInstance, ViewAssemblies = new List<Assembly>() { this.GetType().Assembly }, };
services.AddSingleton<IViewManager>(new ViewManager(viewManagerConfig)); services.AddTransient<MessageBoxView>();
services.AddSingleton<IWindowManagerConfig>(this); services.AddSingleton<IWindowManager, WindowManager>(); services.AddSingleton<IEventAggregator, EventAggregator>();
services.AddTransient<IMessageBoxViewModel, MessageBoxViewModel>(); // Not singleton! // Also need a factory services.AddSingleton<Func<IMessageBoxViewModel>>(() => new MessageBoxViewModel()); }
/// <summary> /// Override to add your own types to the IoC container. /// </summary> protected virtual void ConfigureIoC(IServiceCollection services) { }
public override object GetInstance(Type type) { return this.ServiceProvider.GetRequiredService(type); }
protected override void Launch() { base.DisplayRootView(this.RootViewModel); }
public override void Dispose() { base.Dispose();
ScreenExtensions.TryDispose(this._rootViewModel); if (this._serviceProvider != null) { this._serviceProvider.Dispose(); } }}
然后新建当前项目的 Bootstrapper
,在这里可以做一些 View 相关的配置和服务注册。
需要注意的是,如果使用 Stylet 默认的 IOC 容器,会自动收集所有的 View 和 ViewModel,但如果使用其他的 IOC 框架,就丢失了这个能力。
需要自己手动注册服务,如下面的
services.AddSingleton<RootViewModel>();services.AddSingleton<RootView>();
暂时没有找到快捷的解决方案,可能需要手写一个 Analyzer 来做预编译处理,自动收集并注册依赖。当然,也可以直接使用 autofac 这样的库,但运行时加载的性能不如预编译处理。
详见: 使用 roslyn 的 Source Generator 自动完成依赖收集和注册
public class Bootstrapper : MicrosoftDependencyInjectionBootstrapper<RootViewModel>{ protected override void OnStart() { // This is called just after the application is started, but before the IoC container is set up. // Set up things like logging, etc }
protected override void Configure() { // This is called after Stylet has created the IoC container, so this.Container exists, but before the // Root ViewModel is launched. // Configure your services, etc, in here }
protected override void ConfigureIoC(IServiceCollection services) { base.ConfigureIoC(services); services.AddSingleton<RootViewModel>(); services.AddSingleton<RootView>(); }
protected override void OnLaunch() { // This is called just after the root ViewModel has been launched // Something like a version check that displays a dialog might be launched from here }
protected override void OnExit(ExitEventArgs e) { // Called on Application.Exit }
protected override void OnUnhandledException(DispatcherUnhandledExceptionEventArgs e) { // Called on Application.DispatcherUnhandledException }}
如何在WPF项目中使用Hosting管理应用的配置、日志、服务等_哔哩哔哩_bilibili
原文链接: https://cloud.tencent.com/developer/article/2481574
本作品采用 「署名 4.0 国际」 许可协议进行许可,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。