Dependency Injection in .NET Core Console app using Generic HostBuilder
In this post, we shall learn how to perform dependency injection in the .NET Core Console application using Generic HostBuilder.
We already learned one more approach of DI using Service collection and ServiceProvider in Console Application.
Until now and still many implementation-prefer and rely on service collection classes for registering the dependency and using it through DI container.
Today in this article, we will cover below aspects,
Let’s look into how to use generic HostBuilder to create DI Container and inject the required dependency within the Console app .NET Core application.
Getting started
Here I am using .NET Core 3.1 Console application,
Similar to the already discussed article in the previous post on DI here is the project structure we shall be dealing with. I shall be using the same sample and performing DI but we will be using .NET Core 3.1.
Creating Generic HostBuilder
Generic HostBuilder was introduced in .NET Core 2.1 and designed to be used for both Non-HTTP and HTTP workloads.
The HostBuilder class is available from the following namespace,
using Microsoft.Extensions.Hosting;
HostBuilder implements the IHostBuilder interface.
Please install the NuGet package from Nuget Package manager or PMC,
PM> Install-Package Microsoft.Extensions.Hosting -Version 3.1.1
DI Container
Please create Generic HosBuilder and register the dependencies that need to inject. These changes can be implemented in the Main() method.
var builder = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddLogging(configure => configure.AddConsole());
services.AddTransient<MyApplication>();
services.AddScoped<IBusinessLayer, BusinessLayer>();
services.AddSingleton<IDataAccessLayer, CDataAccessLayer>();
})
Initialize the Host
Initialize the Host with all dependencies,
_host = builder.Build();
OR
By using generic host builder CreateDefaultBuilder
host = Host.CreateDefaultBuilder()
.ConfigureServices((hostContext, services) =>
{
}).Build();
Here we are considering class MyApplication as the entry point for all other classes and business objects and their action.
However, you can add an additional layer addressing the separation of concern if needed.
All the services registered using HostBuilder are now available to use as per the need and can be injected using Construction injection.
The lifetime management of those services will be taken care of by HostBuilder and we need not worry about disposing of them.
Initialize the CreateScope
Please add the below code in the Main() method,
using (var serviceScope = host.Services.CreateScope())
{
var services = serviceScope.ServiceProvider;
try
{
var myService = services.GetRequiredService<MyApplication>();
await myService.Run();
Console.WriteLine("Success");
}
catch (Exception ex)
{
Console.WriteLine("Error Occured");
}
}
Below is the class MyApplication executing the business workflow.
We are injecting logger and business objects as defined and registered in the scope using the HostBuilder DI container.
public class MyApplication
{
private readonly ILogger _logger;
private readonly IBusinessLayer _business;
public MyApplication(ILogger<MyApplication> logger, IBusinessLayer business)
{
_logger = logger;
_business = business;
}
internal async Task Run()
{
_logger.LogInformation("Application {applicationEvent} at {dateTime}", "Started", DateTime.UtcNow);
_business.PerformBusiness();
_logger.LogInformation("Application {applicationEvent} at {dateTime}", "Ended", DateTime.UtcNow);
Console.WriteLine("PRESS <ENTER> TO EXIT");
Console.ReadKey();
}
}
Let’s execute the application and capture the event and action,
Note: Above console logs were intentionally made it to the console view so that events can be captured.
If interested to know on one more approach, please see below post,
Handling Start and Stop Events
Host lifetime can be controlled using the below-supported methods.
public async Task StartAsync()
{
_host.StartAsync();
}
public async Task StopAsync()
{
using (_host)
{
await _host.StopAsync(TimeSpan.FromSeconds(10));
}
}
How to enable configuration loading using DI
You can very much load configuration from different sources like JSON, INI, or XML files in .NET Core Console or Windows or WPF application easily.
I have covered the loading of Apsetting.json or Custom JSON file loading in the below article in detail,
HostBuilder Vs CreateDefaultBuilder
One can create a host builder using generic host builder CreateDefaultBuilder a .NET and ASP.NET Core. It helps us to provide accessing application configuration, user secretes, getting access to environmental information by default out of the box.
Can we make the above code better?
Please let me know if you have any better suggestions and please sound off your comments below.
Summary
Today we learned one more approach for leveraging the Dependency Injection (DI) in Console application in the .NET Core ecosystem. We learned that using HostBuilder we can easily leverage DI in Desktop or Forms applications and can create highly maintainable and extensible Win Form or Desktop applications.
Please bookmark this page and share it with your friends. Please Subscribe to the blog to receive notifications on freshly published(2024) best practices and guidelines for software design and development.
Thanks a lot, this article helped me fixed a problem of using HttpClient Factory in console application. Thinking if can have this code in separate class – host.Services.CreateScope
Unit / Integration tests available?
Hello TeaMohn- Thanks for the query. You can very much write Unit and integration test easily being IoC introduction brings you programming by abstraction. I shall soon put some sample examples around it.