Dec 04 2023
Sponsored
• If you have ever used Postman to debug and write tests for your REST APIs, guess what, those are the same concepts you need to know for writing tests for your gRPC requests in Postman For more info about gRPC, they created a great beginner article here .
Many thanks to the sponsors who make it possible for this newsletter to be free for readers. Become a sponsor.
What is Background task? What is Hosted Service? A Background Task in .NET typically refers to any operation that runs in the background , separate from the main flow of your application. This can include tasks like processing data, performing I/O operations, or any other long-running processes that you don't want to run on the main thread because they might block the user interface or the main operation of your application. A Hosted Service in .NET, specifically in the context of ASP.NET Core, is a service that is hosted within the application's process . It's a way to run long-running background tasks that are tied to the lifecycle of the application. In today's article, I'll explore a recently introduced aspect of the Microsoft.Extensions.Hosting library, which has been part of .NET 8 from its fourth preview, specifically focusing on how it impacts hosted services. Let's dive in...
In earlier versions leading up to .NET 8, the initiation and termination of hosted services within the framework were managed in a sequential manner. Specifically, each service registered as an IHostedService in the Dependency Injection (DI) container was started one after the other. This process involved invoking the StartAsync method for each service and waiting for its completion before moving on to the next one . While this approach generally did not pose significant issues for most applications, there were scenarios where it could lead to complications. For example, if a hosted service executed a lengthy process in its StartAsync method, it could inadvertently delay the startup of subsequent services in the application . It is advisable to minimize the workload in the StartAsync method, but the potential for a slow service to hinder the overall application startup remained a concern prior to the introduction of .NET 8. Let's see the example of how the background service was implemented before .NET 8:
public class SomeService : IHostedService{ public async Task StartAsync(CancellationToken cancellationToken) { Console.WriteLine("Start Service"); await Task.Delay(60000); //1 minute } public async Task StopAsync(CancellationToken cancellationToken) { Console.WriteLine("Stop Service"); }}
DI registration:
builder.Services.AddHostedService<SomeService>();
So what is the problem here? As I mentioned above, StartAsync will be started and will have to wait for it to finish before moving on to the next service. At this point the application won't actually start yet because DI hasn't registered all the services.

I simulated a job that takes 6 seconds and as you can see, 6 seconds passed before the application started. This can be a problem. But there is a solution.
In .NET 8, you now have the option to start or stop your services at the same time, instead of one after the other. This is done by changing the settings in HostOptions . If you want all your services to start together, turn on the ServicesStartConcurrently option. And if you want them to stop at the same time, there's a setting for that too, called ServicesStopConcurrently . Let' take a look on the example:
builder.Services.Configure<HostOptions>(options =>{ options.ServicesStartConcurrently = true; options.ServicesStopConcurrently = true;}); builder.Services.AddHostedService<SomeService>();
The result of this - other services started without any delay.

More control over hosted services .NET 8 introduced a new interface for hosted services - IHostedLifeCycleService . The reason for this is that we don't have much control over the services within the StartAsync() and StopAsync() methods. This interface abstracts 4 more new methods: • StartingAsync • StartedAsync • StoppingAsync • StoppedAsync
public class SomeService : IHostedLifecycleService{ public async Task StartAsync(CancellationToken cancellationToken) { Console.WriteLine("Start Service"); } public async Task StartedAsync(CancellationToken cancellationToken) { Console.WriteLine("Started Service"); } public async Task StartingAsync(CancellationToken cancellationToken) { Console.WriteLine("Starting Service"); } public async Task StopAsync(CancellationToken cancellationToken) { Console.WriteLine("Stop Service"); } public async Task StoppedAsync(CancellationToken cancellationToken) { Console.WriteLine("Stopped Service"); } public async Task StoppingAsync(CancellationToken cancellationToken) { Console.WriteLine("Stopping Service"); }}
This allows us to have full control over hosted services, while they starting (Starting), during their startup (Start), and when they are started (Started) - same for Stop, also.
Before .NET 8, when an app started, its hosted services would start one after the other. Each service had to finish starting before the next one could begin. This usually didn't cause problems, but sometimes a slow service could delay the whole app from starting. In .NET 8, two new features let us start or stop services simultaneously, instead of one after another. You can turn this on by changing the settings in HostOptions for any services you're using. In addition, now you can have a full control over Hosted Services by implementing a new interface IHostedLifecycleService which comes with 4 new methods for controlling the service (StartedAsync, StartingAsync, StoppedAsync, StoppingAsync). Install .NET 8 SDK and test, I'm sure you will see the benefits of this.
For more on background processing, see Background tasks and how to use them. If you need scheduled recurring jobs, check out Job Scheduling with Coravel or Jobs in .NET with Hangfire.
In .NET 8, you can start and stop hosted services concurrently instead of sequentially. Set ServicesStartConcurrently = true and ServicesStopConcurrently = true in HostOptions. This eliminates the startup bottleneck where a slow StartAsync would block all other services from starting.
IHostedLifecycleService is a new interface that extends IHostedService with four additional lifecycle methods: StartingAsync, StartedAsync, StoppingAsync, and StoppedAsync. These give you fine-grained control over what happens before, during, and after a hosted service starts or stops.
Use BackgroundService (which implements IHostedService) when you need a long-running background loop. Use IHostedService directly when you need custom startup/shutdown logic without a continuous loop. In .NET 8+, consider IHostedLifecycleService when you need precise lifecycle hooks.
That's all from me today.
Stop arguing about code style. In this course you get a production-proven setup with analyzers, CI quality gates, and architecture tests — the exact system I use in real projects. Join here.
Not sure yet? Grab the free Starter Kit — a drop-in setup with the essentials from Module 01.
Design Patterns that Deliver — Solve real problems with 5 battle-tested patterns (Builder, Decorator, Strategy, Adapter, Mediator) using practical, real-world examples. Trusted by 650+ developers.
Just getting started? Design Patterns Simplified covers 10 essential patterns in a beginner-friendly, 30-page guide for just $9.95.
Every Monday morning, I share 1 actionable tip on C#, .NET & Architecture that you can use right away. Join here.
Join 20,000+ subscribers who mass-improve their .NET skills with actionable tips on C#, Architecture & Best Practices.
Subscribe to the TheCodeMan.net and be among the 20,000+ subscribers gaining practical tips and resources to enhance your .NET expertise.