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
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Extensions.Hosting.AsyncInitialization" Version="3.0.1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Extensions.Hosting.AsyncInitialization --version 3.0.1
#r "nuget: Extensions.Hosting.AsyncInitialization, 3.0.1"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// 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

NuGet version GitHub Actions Workflow Status

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

  1. Install the Extensions.Hosting.AsyncInitialization NuGet package:

    Command line:

    dotnet add package Extensions.Hosting.AsyncInitialization
    

    Package manager console:

    Install-Package Extensions.Hosting.AsyncInitialization
    
  2. 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
        }
    }
    
  3. Register your initializer(s) in the same place as other services:

    services.AddAsyncInitializer<MyAppInitializer>();
    
  4. In the Program class, replace the call to host.RunAsync() with host.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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (3)

Showing the top 3 NuGet packages that depend on Extensions.Hosting.AsyncInitialization:

Package Downloads
Amaury.Store.DynamoDb

Event Store implementation in AWS DynamoDb to Amaury

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 17,564 2/26/2024
3.0.0 49,746 9/1/2023
2.0.0 57,743 4/5/2023
1.0.0 929,829 3/9/2020
1.0.0-beta.1 20,805 9/28/2019
1.0.0-alpha001 1,155 7/24/2019