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