.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
1 添加引用
// csproj
<ItemGroup>
<PackageReference Include="Stylet" Version="1.3.7" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0-rc.2.24473.5" />
</ItemGroup>
2 修改 App.xaml
因为要手动使用 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>
3 App.xaml.cs
添加 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;
}
}
4 Stylet Bootstrapper
因为不在使用 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://www.cnblogs.com/jasongrass/p/18540534
标签:AddSingleton,void,Hosting,override,protected,构建,services,WPF,App From: https://www.cnblogs.com/jasongrass/p/18540534