Building .NET Core console applications with IHost and HostBuild to take advantage of IHostedService, graceful shutdown, dependency injection, logging, hostbuilder, configuration and more.

When building services for data processing you do not always need a user interface. An IHost is very capable of hosting such an application in a console application as headless service. The IHost does give you a number of advantages like graceful shut down, dependency injection, logging, and configuration. When running long processing tasks in Docker containers, graceful shut down helps you to keep the state of your application consistent. This post explains how making use of the generic IHost in .NET Core for headless services.

Creating a console application based on IHost

A newly created console application seems to be very empty compared to a new web application. You do only get a Console.WriteLine("Hello World") for free. There is no set up for configuration, logging or dependency injection. A web application gives you an IWebHost (built with the WebHostBuilder) which provides services to your application. The IHost and HostBuilder give you a similar experience in a console application.

To get started IHost and HostBuilder you must add the Nuget package Microsoft.Extensions.Hosting . This package contains all the building blocks to create an IHost in which you can host your application. When using the RunConsoleAsync, you do not have to create the IHost itself locally. Everything to run the service is done in the extension method RunConsoleAsync. The code running a hosted service (MyService is of type IHostedService):

class Program { static async Task Main(string[] args) { await new HostBuilder() .ConfigureServices((hostContext, services) => { services.AddHostedService(); }) .RunConsoleAsync(); } }

The HostingHostBuilderExtensions gives you an easy way of configuring your host services. The RunConsoleAsync will start the services and waits on an exit signal in the application. There are the following extension available:

ConfigureAppConfiguration – Sets up the configuration

ConfigureContainer – Enables configuring the instantiated dependency container

ConfigureLogging – Configures logging

ConfigureServices – Adds services to the dependency container

RunConsoleAsync – Enables console support

UseConsoleLifetime – Listens for shutdown signals

UseContentRoot – Specify the content root directory

UseEnvironment – Specify the environment

Most extension can be called multiple times where the result is additive.

The following code is an example of a very simple implementation of an IHostedService. More on IHostedServices: ASP.NET Core background processing with IHostedService

public class MyService : IHostedService, IDisposable { private Timer _timer; public MyService() { } public Task StartAsync(CancellationToken cancellationToken) { Console.WriteLine("Timed Background Service is starting."); _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5)); return Task.CompletedTask; } private void DoWork(object state) { Console.WriteLine("Timed Background Service is working."); } public Task StopAsync(CancellationToken cancellationToken) { Console.WriteLine("Timed Background Service is stopping.2"); _timer?.Change(Timeout.Infinite, 0); return Task.CompletedTask; } public void Dispose() { _timer?.Dispose(); } }

The MyService runs as a IHostedService in the Host. You can run multiple IHostedService in one host.

Logging

Logging is very useful in your hosted services. It can be added with the extension method ConfigureLogging. Adding logging to a IHost is the same as in a WebHost:

.ConfigureServices((hostContext, services) => { services.AddLogging(); (...) }) .ConfigureLogging((hostContext, configLogging) => { configLogging.AddConsole(); configLogging.AddDebug(); }

The usage of logging is then as follows:

public class MyService : IHostedService, IDisposable { private readonly ILogger _logger; private Timer _timer; public MyService(ILogger logger) { _logger = logger; }

Graceful shutdown

When the console application gets a shutdown signal the StopAsync methods in the hosted services are called. In the StopAsync method, you can wait till the processing is ready. When you implement IDisposible, the Dispose method is called to release any unmanaged resources. This is done after the StopAsync method is finished.

Final thoughts

When you have parts of your application or service that do mostly data processing and do not need a user interface, a console application with one or more IHostedServices can be very useful. A console application running an IHost can be ideal within Docker containers. When the container is shut down, the processing can stop gracefully. Besides that, the Dependency Injection gives you many options to test your code. Many reasonsto add the IHost and HostBuilder in your console application.