ASP.NET Core Dependency Injection – How to Register Generic Types Exploring how generic types can be registered with the built-in Microsoft DI container

Since its release, ASP.NET Core has shipped with a “basic” Dependency Injection (DI) container included. This supports the functionality required to run the framework which was built from the ground up to support the use of DI throughout.

The ASP.NET documentation describes some general information about the use of DI in ASP.NET Core.

The documentation for the DI container (ServiceProvider) claims that its quite basic and not a replacement for more fully featured containers such as AutoFac or StructureMap for example. In my experience, for many of my requirements it has proved quite sufficient. In this short post I want to explore a less common registration requirement that may exist for some developers.

Imagine a scenario where you want to register a generic interface and a generic implementation with the ASP.NET Core DI container. In ASP.NET Core itself, an example of this use case is the ILogger<T> interface. We can ask for an ILogger<T> in constructors of our Controllers for example, where T is the Type that the logger will be logging for.

To put this more concretely; if we have a ValuesController and we want to log caught errors from our Actions, we can require an ILogger<ValuesController> in our constructor for the ValuesController. When the controller is constructed by the framework it will receive an implementation of the generic Logger<T> for our provided Type parameter. Under the covers the ILoggerFactory will use the type name to return the appropriate Logger. Messages logged via that logger will then include the full name of the Type (Namespace.ValuesController) when logged to the console for example.

A common way to register services with the ServiceCollection is using the generic extension methods. To add a Singleton registration for an interface and it’s concrete type for example we can call…

serviceCollection.AddSingleton<IService, MyService>();

The signature for the AddSingleton method is…

public static IServiceCollection AddSingleton<TService, TImplementation>(this IServiceCollection serviceswhere TService : class where TImplementation : class, Tservice

This works well for most scenarios but doesn’t work if we want to register generic services.

For a slightly contrived example, let’s say we have an interface like this…

And an implementation like this…

We want to be able to ask for an IThing<SomeType> in the constructor of a consumer which will get the correct GenericThing<SomeType> injected.

In this case we can use a different extension method on the ServiceCollection that accepts the types as parameters. Our registration would then look like this…

We now have our generic interface and implementation registered correctly. We can now consume this via DI wherever we need it injected.

Using HostBuilder and the Generic Host in .NET Core Microservices Exploring a simple pattern for cross-cutting concerns in console based services.


The “generic” Host and HostBuilder are components  of a new feature set coming with the release of .NET Core 2.1. A use case of them is to simplify the creation of console based services by providing a pattern for adding cross-cutting concerns such as dependency injection, configuration and logging.


Since ASP.NET Core 1.0 was released we’ve had the WebHostBuilder class which allows us to configure and build a WebHost. This then handles the lifetime of the application while the server (Kestrel) accepts and processes HTTP requests. In ASP.NET Core 2.0 the WebHostBuilder got some further refinement and simplification. The WebHostBuilder allows us to do things such as configuring services with a dependency injection container; quite often the container provided by Microsoft as part of ASP.NET Core. The WebHostBuilder also allows us to load configuration from multiple sources into a final configuration representation of Key/Value pairs.

The works extremely well for ASP.NET Core web applications, but there were no similar options in the framework for other types of application, until now!

NOTE: Please bear in mind that this post is written based on the ASP.NET Core 2.1 preview 1 release. Therefore, things may change during the public previews and also before the final release of 2.1 based on feedback received during those previews.

Introducing IHost and the HostBuilder

A new option available to developers working with .NET Core 2.1 is the new “generic” Host which enables developers to easily set up cross-cutting concerns such as logging, configuration and dependency injection for non-web focused applications. The team have realised that having the host tied to the concern of HTTP was perhaps not an ideal solution since many of these things are common requirements in other application types.

An example of where this could be used is in a console application which needs to run background processing tasks, perhaps handling messages on a queue for example. These types of services are now pretty common in a cloud native, container based architecture.

In the current 2.0 version of .NET Core it is certainly possible to utilise the logging, configuration and DI libraries within a console application. At work we have a number of microservices which do things such as processing messages from queues and data enriching tasks. We have to manually include and setup each of those common concerns ourselves.  Although this is possible, there’s some plumbing required to get things like DI setup within the application.

Building a Host

To create a Host we can use the new HostBuilder, which has a similar set of methods and extensions as the existing WebHostBuilder. The patterns should therefore be familiar to anyone working with ASP.NET Core currently.

There is one main difference to be aware of. The HostBuilder doesn’t provide an extension method that allows you to use a startup class as we can with the WebHostBuilder. This decision was made primarily to avoid the need to create two separate DI containers behind the scenes. With the generic host, a single service collection is configured and then used to build a the final service provider.

In the Main method for your application you can start by creating a HostBuilder and then use extension methods to register services with DI, read configuration and configure the logging that you need for your application.

The best way to explain the feature is with an example. If you want to view the full sample code you can pull it from GitHub.

If we take a look at the Main method for this console application, we can explore the creation of a Host for our application.

If you’ve used ASP.NET Core at all and have seen the WebHost builder, particularly in the 1.0 time frame, this might look quite familiar. We start by creating a HostBuilder which we can then use to define the Host we want to create. The first method in this example is the ConfigureAppConfiguration method. This method allows us to configure which configuration providers should be used to construct the final representation of configuration values for our application.

This is identical to the way that configuration can be customised when using the WebHostBuilder. In this example we have said that we want configuration values to be first read from an appsettings.json file, followed by environment variables and finally from any arguments passed into the application.

Next we call ConfigureServices which just as with the WebHostBuilder, allows us to register services with the ServiceCollection. Registration is performed using extension methods on the ServiceCollection and once complete, will enable us to get instances of those registrations wherever DI is available in our application.

In this case the first of these adds the ASP.NET Core Options services and the second sets up the registration for the IOptions binding. The final service registration is something I’ll come to a little later on.

The final section, ConfigureLogging as you might expect sets up logging for the application. In this case we add console logging, which uses the values from the application configuration to determine what to log.

The logging config in this sample is the same as found in a default ASP.NET Core web applications created using the templates.

The final step is to call RunConsoleAsync on the HostBuilder which builds and starts the application. It will then keep running until CTRL+C is used to trigger it to shutdown.

Getting Stuff Done

A service wouldn’t be much good if we left it here. At this point we just have a console application running, but not actually doing anything useful. Therefore we need a way to define the work which our application should perform.

The pattern that is recommended for this style of service is to utilise the new IHostedService feature, first introduced in ASP.NET Core 2.0. I wrote about this in a previous blog post.

Here we have a basic IHostedService implementation which will be run within this service…

I won’t go too deep into this code but I will summarise what it’s doing. When the application is started, it will call StartAsync on this service. Within that method we create a Timer which does some work every five seconds.

The work itself is defined in DoWork. Here is simply users the ILogger to log a message as information. This includes a message retrieved from the application configuration. This is accessed through the IOptions object passed into the service by DI.

At shutdown, StopAsync is called and the service cleans up a little before the application is killed. This is quite a contrived example but I wanted to keep things simply and focus on how the pieces fit together.

With the IHostedService implementation defined we simply have to register it with the DI container using the following common in ConfigureServices (which we saw earlier).

services.AddSingleton<IHostedService, PrintTextToConsoleService>();

We could add multiple hosted services if we needed to have various things running within this service.


There are quite a few cases for using this new “generic” Host concept. In this post we’ve explored a quite basic example, however I wouldn’t need much more than this to simplify a few of the microservices in our environment. Having a single common pattern for web applications as well as services, with easy access to things like DI, logging and configuration is extremely welcome.