I'm trying to start a BackgroundService assigned to a services.HostedService of an IHostBuilder.
IHostBuilder definition:
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();
}
);
});
}
but the only possible way I found to start the HostedService is by running this:
await CreateHostBuilder().Build().RunAsync();
Finally, the problem happens because on this approach, the thread locks on that line and don't let me run the common block code to start the Form itself:
Application.Run(new MainForm());
The same happens if I run the Form first, the thread'd lock on that line and wouldn't let me call the RunAsync of HostBuilder.
I also tried to declare all HostBuilder scope on the Form class and start the BackgroundService on it's constructor, but then I wouldn't be able to run the Async method on a ctor.
What I'm currently trying (but no success yet) is to call the Form without the Application.Run (and still don't know all the side effects by doing this) so I can run the HostBuilder next.
My entire Program class now:
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();
}
);
});
}
}
What'd be the workaround for this considering .NET 5 and ignoring BackgroundWorker component?
CodePudding user response:
Solution by Nkosi, on comments:
Make another hosted service to invoke
Application.Run
that way when you run the host, the UI aspect and background worker hosted services will be started
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;
}
}
and the 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...
});
}
}