I know a IHostedService
that runs only one time sounds like a console application, but the reason I want to use it instead of a plain console application is:
By using the following code, I'm able to somewhat achieve this one-time behaviour, however, I could not find a way to gracefully exit the app after it finishes.
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) => { services.AddHostedService<StartUp>(); });
}
Where StartUp
is a simple IHostedService
public class StartUp:IHostedService
{
private ILogger<StartUp> _logger;
public StartUp(ILogger<StartUp> logger)
{
_logger = logger;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("start async");
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("stop async");
return Task.CompletedTask;
}
}
How can I stop the app gracefully? Or if this is completely wrong, how should I implement this one-time application?
Since . NET Core 2.0, the framework provides a new interface named IHostedService helping you to easily implement hosted services. The basic idea is that you can register multiple background tasks (hosted services) that run in the background while your web host or host is running, as shown in the image 6-26.
The BackgroundService token source is cancelled by the StopAsync method. So to cancel the CustomService async work you have to call the StopAsync method. This cancel token provided to the ExecuteAsync method as parameter.
Yes, you can achieve that by injecting IHostApplicationLifetime
into your hosted service.
Example:
public class StartUp:IHostedService
{
private readonly IHostApplicationLifetime _host;
private ILogger<StartUp> _logger;
public StartUp(IHostApplicationLifetime host, ILogger<StartUp> logger)
{
_host = host;
_logger = logger;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("start async");
_host.StopApplication();
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("stop async");
return Task.CompletedTask;
}
}
You can also set exit code by setting Environment.ExitCode
.For example:
Environment.ExitCode = 0;
_host.StopApplication();
If you are just using IHostedService
as a workaround for the missing DI and ILogger
you can also setup DI with the ILogger
and IConfiguration
directly without IHostedService
public class Program
{
public static async Task Main(string[] args)
{
var configBuilder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: true);
var config = configBuilder.Build();
var sp = new ServiceCollection()
.AddLogging(b => b.AddConsole())
.AddSingleton<IConfiguration>(config)
.AddSingleton<IFooService, FooService>()
.BuildServiceProvider();
var logger = sp.GetService<ILoggerFactory>().CreateLogger<Program>();
logger.LogDebug("Starting");
var bar = sp.GetService<IFooService>();
await bar.DoAsync();
}
}
With this setup your code is just running once, can resolve every service you register in the ServiceCollection
and no need of a Host
to start
Example: .netfiddle
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With