Extensions.Hosting.AsyncInitialization
3.0.1
dotnet add package Extensions.Hosting.AsyncInitialization --version 3.0.1
NuGet\Install-Package Extensions.Hosting.AsyncInitialization -Version 3.0.1
<PackageReference Include="Extensions.Hosting.AsyncInitialization" Version="3.0.1" />
paket add Extensions.Hosting.AsyncInitialization --version 3.0.1
#r "nuget: Extensions.Hosting.AsyncInitialization, 3.0.1"
// Install Extensions.Hosting.AsyncInitialization as a Cake Addin #addin nuget:?package=Extensions.Hosting.AsyncInitialization&version=3.0.1 // Install Extensions.Hosting.AsyncInitialization as a Cake Tool #tool nuget:?package=Extensions.Hosting.AsyncInitialization&version=3.0.1
Extensions.Hosting.AsyncInitialization
A simple helper to perform async application initialization and teardown for the generic host in .NET 6.0 or higher (e.g. in ASP.NET Core apps).
Basic usage
Install the Extensions.Hosting.AsyncInitialization NuGet package:
Command line:
dotnet add package Extensions.Hosting.AsyncInitialization
Package manager console:
Install-Package Extensions.Hosting.AsyncInitialization
Create a class (or several) that implements
IAsyncInitializer
. This class can depend on any registered service.public class MyAppInitializer : IAsyncInitializer { public MyAppInitializer(IFoo foo, IBar bar) { ... } public async Task InitializeAsync(CancellationToken cancellationToken) { // Initialization code here } }
Register your initializer(s) in the same place as other services:
services.AddAsyncInitializer<MyAppInitializer>();
In the
Program
class, replace the call tohost.RunAsync()
withhost.InitAndRunAsync()
:
public static async Task Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
await host.InitAndRunAsync();
}
This will run each initializer, in the order in which they were registered.
Teardown
In addition to initialization, this library also supports performing cleanup tasks when the app terminates. To use this, make your initializer implement IAsyncTeardown
, and implement the TeardownAsync
method:
public class MyAppInitializer : IAsyncTeardown
{
public MyAppInitializer(IFoo foo, IBar bar)
{
...
}
public async Task InitializeAsync(CancellationToken cancellationToken)
{
// Initialization code here
}
public async Task TeardownAsync(CancellationToken cancellationToken)
{
// Cleanup code here
}
}
When you run the application with InitAndRunAsync
, each initializer that supports teardown will be invoked in reverse registration order, i.e.:
- initializer 1 performs initialization
- initializer 2 performs initialization
- application runs
- initializer 2 performs teardown
- initializer 1 performs teardown
Lifetime and state considerations
When you create an initializer that also performs teardown, keep in mind that it will actually be resolved twice:
- once for initialization
- once for teardown
Initialization and teardown each runs in its own service provider scope. This means that a different instance of your initializer will be used for initialization and teardown, so your initializer cannot keep state between initialization and teardown, unless it's registered as a singleton.
If you do register your initializer as a singleton, keep in mind that it must not depend on any scoped service, otherwise the scoped service will live for the whole lifetime of the application; this is an anti-pattern known as captive dependency.
Advanced usage
If, for some reason, you need more control over the application execution process, you can manually call the InitAsync
and TeardownAsync
methods on the host. If you do that, keep in mind that TeardownAsync
cannot be called after host.RunAsync()
completes, because the host will already have been disposed:
// DO NOT DO THIS
await host.InitAsync();
await host.RunAsync();
await host.TeardownAsync(); // Will fail because RunAsync disposed the host
So you will need to manually call StartAsync
and WaitForShutdownAsync
, and call TeardownAsync
before you dispose the host:
await using (var host = CreateHostBuilder(args).Build())
{
await host.InitAsync();
await host.StartAsync();
await host.WaitForShutdownAsync();
await host.TeardownAsync();
}
Cancellation
The InitAndRunAsync
, InitAsync
and TeardownAsync
all support passing a cancellation token to abort execution if needed. Cancellation will be propagated to the initializers.
In the following example, execution (including initialization, but not teardown) will be aborted when Ctrl + C
keys are pressed :
public static async Task Main(string[] args)
{
using CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
// The following line will hook `Ctrl` + `C` to the cancellation token.
Console.CancelKeyPress += (source, args) => cancellationTokenSource.Cancel();
var host = CreateHostBuilder(args).Build();
await host.InitAndRunAsync(cancellationTokenSource.Token);
}
As mentioned above, when using InitAndRunAsync
, the cancellation token will not be passed to the teardown. This is because when your application is stopped, you typically still want the teardown to occur. Instead, teardown will run with a default timeout of 10 seconds (you can also specify a timeout explicitly).
If you don't want this behavior, you can manually call InitAsync
and TeardownAsync
as explained in the previous section.
Migration from 2.x or earlier
If you were already using this library prior to version 3.x, your code would typically look like this:
await host.InitAsync();
await host.RunAsync();
This will still work without changes. Just keep in mind that, as explained in the previous section, adding a call to host.TeardownAsync()
after host.RunAsync()
will not work. If you need teardown, the simplest way is to remove the explicit call to InitAsync
, and call InitAndRunAsync
instead of RunAsync
.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net6.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 6.0.0)
- Microsoft.Extensions.Hosting.Abstractions (>= 6.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 6.0.0)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Extensions.Hosting.AsyncInitialization:
Package | Downloads |
---|---|
SmartHead.Essentials.Application
SmartHead.Essentials.Application |
|
SolidOps.NORAD.Core
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
3.0.1 | 141,168 | 2/26/2024 |
3.0.0 | 74,643 | 9/1/2023 |
2.0.0 | 68,215 | 4/5/2023 |
1.0.0 | 1,044,977 | 3/9/2020 |
1.0.0-beta.1 | 21,958 | 9/28/2019 |
1.0.0-alpha001 | 1,181 | 7/24/2019 |