如何使用BackgroundService和依赖注入运行Winforms?

Igo*_*ues 3 .net c# dependency-injection background-service winforms

我正在尝试启动分配给IHostBuilder的services.HostedService的BackgroundService。

IHostBuilder定义:

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();
                }
                );
            });
    }
Run Code Online (Sandbox Code Playgroud)

但我发现启动HostedService 的唯一可能的方法是运行以下命令:

await CreateHostBuilder().Build().RunAsync();   
Run Code Online (Sandbox Code Playgroud)

最后,问题发生是因为在这种方法中,线程锁定在该行上,并且不允许我运行公共块代码来启动表单本身:

Application.Run(new MainForm());
Run Code Online (Sandbox Code Playgroud)

如果我先运行表单,也会发生同样的情况,线程会锁定该行,并且不会让我调用HostBuilder的RunAsync。

我还尝试在 Form 类上声明所有HostBuilder范围,并在其构造函数上启动BackgroundService,但随后我将无法在 ctor 上运行 Async 方法。

我目前正在尝试(但尚未成功)的是在没有Application.Run 的情况下调用表单(并且仍然不知道这样做的所有副作用),以便我接下来可以运行HostBuilder。

我现在的整个课程:

static class Program
{
    [STAThread]
    private static async Task Main()
    {
        Application.SetHighDpiMode(HighDpiMode.SystemAware);
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);            

        var host = CreateHostBuilder().Build();

        host.Services.GetRequiredService<AuthenticationForm>().Show();

        await host.RunAsync();
    }
    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();
                }
                );
            });
    }
}
Run Code Online (Sandbox Code Playgroud)

考虑到.NET 5并忽略BackgroundWorker组件,解决方法是什么?

Igo*_*ues 6

Nkosi 的解决方案,评论:

当您运行主机时,创建另一个托管服务以这种方式调用Application.Run,UI 方面和后台工作托管服务将启动

class StartProgram : BackgroundService
{
    private readonly IServiceProvider _services;
    public StartProgram(IServiceProvider services)
    {
        this._services = services;
    }
    protected override Task ExecuteAsync(CancellationToken stoppingToken)
    {
        Application.SetHighDpiMode(HighDpiMode.SystemAware);
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run((AuthenticationForm)_services.GetService(typeof(AuthenticationForm)));

        return Task.CompletedTask;
    }
}
Run Code Online (Sandbox Code Playgroud)

和 Program.cs:

static class Program
{
    [STAThread]
    private static async Task Main()
    {
        await CreateHostBuilder().Build().RunAsync();
    }
    private static IHostBuilder CreateHostBuilder()
    {
        return Host.CreateDefaultBuilder()
            .ConfigureServices(services =>
            {
                services.AddHostedService<LicenseControl>();
                services.AddHostedService<StartProgram>();

                #region ETC...
            });
    }
}

  
Run Code Online (Sandbox Code Playgroud)