Introduction

With the new previews of dotnetcore there are new project templates but also a more generic hosting system, instead of having a Web specific host builder or Worker/services host builder there is a new “generic” host which they are all based on. These are all brought together under IHost.

With this and other patterns/practices there are now multiple ways of registering your services. Let’s take a look.

ASP.NET Core 3 Preview 6 New Empty Project

If we take a look at the Empty template the entry point program which starts everything up has a familier look to it (if you are familer with ASP.NET Core 2.x).

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

And the associated Startup class is familier as well.

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapGet("/", async context =>
            {
                await context.Response.WriteAsync("Hello World!");
            });
        });
    }
}

So where in all of this can we register services with IServiceCollection?

Three Registration Points

So far, with the aspnetcore empty template, I have found 3 places where you can register your dependencies.

In Startup.cs

The first place is a familiar place, it is in the Startup class in the ConfigureServices method.

In the webBuilder delegate

The second place is with the IWebHostBuilder delegate in Program. This is accessed at the same point as when you register your Startup class.

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureServices(services =>
            {
                Console.WriteLine("In webBuilder.ConfigureServices ...");
            });
            webBuilder.UseStartup<Startup>();
        });

On the IHostBuilder

The third place is on the IHostBuilder directly. This I explored a little when I was registering services for in the worker project template and registered IClock to be injected into the worker.

Simple Example

This is a simple example of how you can use them all together so we can see which order they get called.

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureServices(services =>
        {
            Console.WriteLine("In HostBuilder.ConfigureServices ...");
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureServices(services =>
            {
                Console.WriteLine("In webBuilder.ConfigureServices ...");
            });
            webBuilder.UseStartup<Startup>();
        })
        .ConfigureServices(services =>
        {
            Console.WriteLine("In HostBuilder.ConfigureServices Again ...");
        });

As you can see you can also chain them together and call the method on the IHostBuilder multiple times.

In Startup the ConfigureServices method has a similar Console.WriteLine method call in so I have emitted it.

When running the above example the running order is probably not surprising.

The output in the console window displays the order in which they are called.

In HostBuilder.ConfigureServices ...
In webBuilder.ConfigureServices ...
In Startup.ConfigureServices ...
In HostBuilder.ConfigureServices Again ...
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development

Potential Usages?

On brief investigation of this new host builder and how the different points get called you can start to see how the IServiceCollection instance can be manipulated at any point during the registration cycle.

A potential use of this could be to make sure certain items are registered before the main application Startup code if you are writing a microservices shell. Or similarly you want to make sure specific items have at least one implementation so you may call TryAddTransient<> in the last call to ConfigureServices to make sure there is at least one. I’m sure there are many more.

Conclusion

We’ve briefly looked at how to register your dependencies in the new IHostBuilder world specfically focusing on the web builder. We’ve looked at the different points where services can be registered and some potential use cases of when they could be used.

I’m sure there are more options and use cases for all of the places which have been discussed. Let me know on Twitter if you have any other crazy or funky usages for the pattern.

Any questions/comments then please contact me on Twitter @WestDiscGolf