.NET5中如何让Winforms结合BackgroundService与依赖注入运行?
解决方案
你遇到的阻塞问题核心原因是IHost.RunAsync()会一直等待宿主进程终止才返回,而Application.Run()同样会阻塞直到UI窗体关闭,二者默认都会占用当前线程,只要调整启动顺序和调用方法即可解决:
核心改动点
不要调用RunAsync(),改用StartAsync()启动宿主:StartAsync()只会完成所有托管服务(包括你注册的BackgroundService)的启动流程就立即返回,不会阻塞当前线程,等UI窗体关闭后再手动调用StopAsync()优雅关闭宿主即可。
完整修改后的Program类代码
static class Program { [STAThread] private static async Task Main() { Application.SetHighDpiMode(HighDpiMode.SystemAware); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); // 构建宿主但不立即阻塞运行 var host = CreateHostBuilder().Build(); // 启动所有托管服务,启动完成后立即返回 await host.StartAsync(); try { // 从DI容器获取启动窗体,保证依赖注入正常生效 var authForm = host.Services.GetRequiredService<AuthenticationForm>(); // 启动UI消息循环,阻塞直到所有窗体关闭 Application.Run(authForm); } finally { // 窗体关闭后优雅停止宿主,等待BackgroundService完成清理 await host.StopAsync(); // 释放宿主资源 host.Dispose(); } } // CreateHostBuilder方法不需要做任何修改,和你之前的实现完全一致 private static IHostBuilder CreateHostBuilder() { return Host.CreateDefaultBuilder() .ConfigureServices(services => { services.AddHostedService<LicenseControl>(); services.AddTransient<Database>(); services.AddTransient<CoreLicense>(); services.AddSingleton<FormSelector>(); services.AddTransient<ClienteForm>(); services.AddTransient<GastoForm>(); services.AddTransient<IngredienteForm>(); services.AddTransient<ProdutoForm>(); services.AddTransient<ReceitaForm>(); services.AddTransient<RelatorioForm>(); services.AddTransient<VendaForm>(); services.AddTransient<MainForm>(); services.AddTransient<ConfiguracoesForm>(); services.AddTransient<UsuarioForm>(); services.AddSingleton<AuthenticationForm>(); services.AddScoped<IBridgeRepository, BridgeRepository>(); services.AddScoped<IClienteRepository, ClienteRepository>(); services.AddScoped<IGastoRepository, GastoRepository>(); services.AddScoped<IIBGERepository, IBGERepository>(); services.AddScoped<IIngredienteRepository, IngredienteRepository>(); services.AddScoped<IProdutoRepository, ProdutoRepository>(); services.AddScoped<IReceitaRepository, ReceitaRepository>(); services.AddScoped<IVendaRepository, VendaRepository>(); services.AddScoped<IUsuarioRepository, UsuarioRepository>(); services.AddLogging( builder => { builder.AddFilter("Microsoft", LogLevel.Warning) .AddFilter("System", LogLevel.Warning) .AddFilter("NToastNotify", LogLevel.Warning) .AddConsole(); } ); }); } }
方案说明
- 完全兼容.NET 5规范,不需要额外引入第三方组件,也不需要使用
BackgroundWorker - 依赖注入功能完全正常,所有窗体、服务的生命周期都由通用主机统一管理
- 退出逻辑优雅:用户关闭窗体后会自动通知
BackgroundService停止,等待后台任务完成清理后再退出进程,不会出现后台任务被强制终止的问题
内容的提问来源于stack exchange,提问作者Igor Henriques
相关产品推荐
相关产品推荐

