Skip to content

Instantly share code, notes, and snippets.

@xiaomi7732
Created March 1, 2024 05:34
Show Gist options
  • Save xiaomi7732/c96c427b3d0ac971bc6c012a634d0a0b to your computer and use it in GitHub Desktop.
Save xiaomi7732/c96c427b3d0ac971bc6c012a634d0a0b to your computer and use it in GitHub Desktop.
Run Async code before hosting get started

Run asynchronous code before hosting get started

The goal

To run some async code before the host get started.

There has been post talking about various techniques before Microsoft.Extensions.Hosting version 8.0.0. For example: https://andrewlock.net/running-async-tasks-on-app-startup-in-asp-net-core-part-1/.

The problem was, it was kind of hard to:

  1. Find a sweet spot to run the code;
    • And by sweet spot, I mean, after all the services in the dependency injection containers are registered but before any hosting code's running.
  2. Run asynchronous but avoid async over sync.

The solution

Now, everything becomes much easier as long as Microsoft.Extensions.Hosting 8.0.0 or above is referenced - and yes, it works with .NET 6 applications too.

What does it provide

There is a new interface in the pacage, named IHostedLifecycleService. Refer here for more details for the interface.

The key take away is that it provides more methods to be called during various steps in starting the host. One of them, StartingAsync will be called after all the services are ready in the DI container, but before the host starts. That's exactly where we would usually want our one off initializing code to run.

Here's how to use it:

  1. Refer to the package Microsoft.Extensions.Hosting;

    • You don't need to do this manually if you are running a .NET 8 application because its already there.
  2. Create a class that implements IHostedLifecycleService. There are several methods to be implemented. Related to our goal is StartingAsync, which runs before any of the regular IHostedService. For example:

    namespace LearnHostedLifetimeService;
    
    public class MyHostedLifetimeService : IHostedLifecycleService
    {
    
        public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
    
        public Task StartingAsync(CancellationToken cancellationToken)
        {
            Console.WriteLine("Starting async. This is expected to be called before {0}.", nameof(DemoRegularHostedService));
            return Task.CompletedTask;
        }
    
        ...
    }
  3. Optionally, we can add a regular Background service and check out the running sequence by ourselves:

    namespace LearnHostedLifetimeService;
    
    public class DemoRegularHostedService : BackgroundService
    {
        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            Console.WriteLine("Execution the {0}", nameof(DemoRegularHostedService));
            return Task.CompletedTask;
        }
    }
  4. Register the hosted lifecycle along with other hosted services:

    builder.Services.AddHostedService<DemoRegularHostedService>(); // Although this is registered earlier, it still executes later.
    builder.Services.AddHostedService<MyHostedLifetimeService>(); // The StartingAsync will be called first.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment