Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/thomaslevesque/extensions.hosting.asyncinitialization
Async initialization for .NET 6.0+ apps using the generic host (e.g. ASP.NET Core apps)
https://github.com/thomaslevesque/extensions.hosting.asyncinitialization
asp-net-core async-initialization csharp dotnet generic-host
Last synced: 7 days ago
JSON representation
Async initialization for .NET 6.0+ apps using the generic host (e.g. ASP.NET Core apps)
- Host: GitHub
- URL: https://github.com/thomaslevesque/extensions.hosting.asyncinitialization
- Owner: thomaslevesque
- License: apache-2.0
- Created: 2019-07-24T13:39:49.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2024-02-26T02:56:23.000Z (11 months ago)
- Last Synced: 2025-01-01T23:08:27.219Z (14 days ago)
- Topics: asp-net-core, async-initialization, csharp, dotnet, generic-host
- Language: C#
- Homepage:
- Size: 54.7 KB
- Stars: 48
- Watchers: 5
- Forks: 7
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# Extensions.Hosting.AsyncInitialization
[![NuGet version](https://img.shields.io/nuget/v/Extensions.Hosting.AsyncInitialization.svg?logo=nuget)](https://www.nuget.org/packages/Extensions.Hosting.AsyncInitialization)
[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/thomaslevesque/Extensions.Hosting.AsyncInitialization/build.yml?branch=master&logo=github)](https://github.com/thomaslevesque/Extensions.Hosting.AsyncInitialization/actions/workflows/build.yml)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](https://www.nuget.org/packages/Extensions.Hosting.AsyncInitialization/) NuGet package:
Command line:
```PowerShell
dotnet add package Extensions.Hosting.AsyncInitialization
```Package manager console:
```PowerShell
Install-Package Extensions.Hosting.AsyncInitialization
```2. Create a class (or several) that implements `IAsyncInitializer`. This class can depend on any registered service.
```csharp
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:
```csharp
services.AddAsyncInitializer();
```4. In the `Program` class, replace the call to `host.RunAsync()` with `host.InitAndRunAsync()`:
```csharp
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:
```csharp
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 teardownInitialization 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](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection-guidelines#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:
```csharp
// 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:
```csharp
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 :
```csharp
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:
```csharp
await host.InitAsync();
await host.RunAsync();
```This will still work without changes. Just keep in mind that, as explained in the Advanced Usage 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`.