X

Config dependency injection in .Net Core console application

Dung Do Tien Oct 13 2020 1236
In this article, I will guide config dependency injection in .Net Core console application. As you know DI is the best way to resolve dependency and initial services. So you can set it up for any project type in .Net Core. About how it works and set up, it's the same with DI in Asp.net Core web application project if you have ever done with Asp.Net Core web app you can very easily set up DI for .Net Core console application.

Required environment:

- Visual Studio 2017 or 2019
- .Net core from version 2.1, in this example I used .net core version 3.1.

To config dependency injection in .Net Core console application, after creating the project you have to install package DependencyInjection from Nuget:

Or you can install from Package Manager with the command below:

Install-Package Microsoft.Extensions.DependencyInjection -Version 3.1.8

And now I create some services to register it to the DI container.

public interface INumberService
{
    List<int> GetEvenNumber(int from, int to);
}

public class NumberService : INumberService
{
    public List<int> GetEvenNumber(int from, int to)
    {
        if (from <= 0 && to <= 0) return null;
        if (from > to) return null;
        List<int> result = new List<int>();
        for(int i = from; i<= to; i++)
        {
            if(i % 2 == 0)
            {
                result.Add(i);
            }
        }

        return result;
    }
}

Inside the Main method of Program.cs file, we can register service to DI container as below:

using Microsoft.Extensions.DependencyInjection;
// Step1: setup our DI
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<INumberService, NumberService>();
//TODO: Add more service here....

After adding service to the DI container, we can call service to execute some method of that service. See some line code as below:

//Step 2: get service 
var serviceProvider = serviceCollection.BuildServiceProvider();
var numberService = serviceProvider.GetService<INumberService>();

var lstNumber = numberService.GetEvenNumber(1, 15);
if(lstNumber != null && lstNumber.Any())
{
    int stt = 0;
    foreach(int number in lstNumber)
    {
        stt++;
        Console.WriteLine(string.Format("Value of item {0} is: {1}", stt, number));
    }
}

In that:

- BuildServiceProvider(): Method helps to create a Microsoft.Extensions.DependencyInjection.ServiceProvider containing services from the provided Microsoft.Extensions.DependencyInjection.IServiceCollection.

- GetService(): Method help get a service object from the service provider. If that service is not found, it will be returned null.

Dispose of all service: After all business code is done, you don’t want to use the serviceProvider resource more, you have to release it to avoid unmanaged resources still existing in the memory ram.

// Step 3: dispose & release all service from service collection
if (serviceProvider is IDisposable)
{
    ((IDisposable)serviceProvider).Dispose();
}

Now we can run the application and see the result:

This is a basic way to use dependency injection in .Net Core console application. In addition, you can use Service Locator for replacement but I think it will be more complicated.

If you want to get service from any class, not only inside of the Main() method, you have to change the serviceProvider variable to the global scope or using the Singleton pattern to create the service provider as below:

The first. I created a ServiceCollectionHelper class to manage all actions of service such as register service to DI container, get service, dispose of service…

public class ServiceCollectionHelper
{
    private static ServiceCollectionHelper _instance;
    private static readonly object ObjLocked = new object();
    private static ServiceProvider _servicePrivider;

    protected ServiceCollectionHelper()
    {
    }

    public static ServiceCollectionHelper Instance
    {
        get
        {
            if (null == _instance)
            {
                lock (ObjLocked)
                {
                    if (null == _instance)
                        _instance = new ServiceCollectionHelper();
                }
            }
            return _instance;
        }
    }

    /// <summary>
    /// Register all service here
    /// </summary>
    public void RegisterService()
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddTransient<INumberService, NumberService>();
        // Add more service here

        _servicePrivider = serviceCollection.BuildServiceProvider();
    }

    /// <summary>
    /// Method help get service from service collection
    /// </summary>
    /// <typeparam name="T">Service you want to get</typeparam>
    /// <returns></returns>
    public T GetService<T>()
    {
        return _servicePrivider.GetService<T>();
    }


    /// <summary>
    /// Dispose sevice collection
    /// </summary>
    public void Dispose()
    {
        if (_servicePrivider is IDisposable)
        {
            ((IDisposable)_servicePrivider).Dispose();
        }
    }
}

Finally, you can register and call service from anywhere if you want. For example, I will code inside of Main() method of Program.cs to replace for first base way above:

ServiceCollectionHelper.Instance.RegisterService();
var numberService2 = ServiceCollectionHelper.Instance.GetService<INumberService>();

var lstNumber2 = numberService.GetEvenNumber(1, 15);
if (lstNumber2 != null && lstNumber2.Any())
{
    int stt = 0;
    foreach (int number in lstNumber2)
    {
        stt++;
        Console.WriteLine(string.Format("Value of item {0} is: {1}", stt, number));
    }
}

ServiceCollectionHelper.Instance.Dispose();

We also get the same result as above. Don’t forget that RegisterService() method you only call one time in the Main() method and the GetService() method you can call from anywhere.

You also can apply this way to config Dependency injection for the Unit test project. I think it's a good option to do.

Conclusion

In this article, I just guide how to config dependency injection in .Net Core console application. I hope it brings some useful knowledge for you. If you have any questions you can leave a comment below for me.

You can refer to the source code from here.

Happy code!!!