Using Dependency Injection in a .NET Core Console/ Desktop Application

Dependency Injection in a NET Core ConsoleDesktop Apps

Today in this article, we will see using Dependency Injection in a .NET Core Console/ Desktop Application.

Unlike ASP.NET Core, an application like Form WPF, or Console apps which are highly useful applications don’t have a Dependency Injection( DI) framework supported by default.

Today in this article, we will cover below aspects,

As we know .NET Core framework has brought in and leveraged the Explicit Dependency Injection (DI) principle very well and almost every functionality/service used in the application can be injected through DI.

Ultimately your container controls the lifetime of services used and the consumer need not have to worry about disposing of them once after every use.

“Only pay for what you use”

It is a simple concept, you inject and use services that you need, making your application highly efficient and lightweight.


There are a lot of benefits of the DI approach like,

  • Separation of concern
  • Independently deployable unit
  • Easily Testable units
  • High performance
  • Easy maintenance

One should also understand that every good pattern, if not used properly for a given context, can become an anti-pattern too. Unlike ASP.NET core applications, we don’t have a pipeline in non-ASP.NET core apps.

So here we shall be using the entry point of applications as a pipeline.

As an example – the Main() method is the entry point for the Console application.

Here we will use the same concept, and create a new entry point called Run(). Importantly this Run will be called using instances that are created using ServiceProvider and ServiceColletion class.

I believe a similar concept of the entry point as pipeline can be leveraged in the Form/WPF Desktop application. I shall surely give it a try in the coming days using .NET Core 3.0.


Getting Started

Here is an example of a project structure ultimately we will be dealing with.

This early structure will give you a clear idea of what ultimately we want to achieve at the end of this article.

Dependency Injection in a NET Core Console

This application looks like a real project which has an Application Layer, a Business Layer, and a Data Access Layer.

I’m here to try to inject all the dependencies required from your app layer using the ServiceColletion class and ServiceProvider class to leverage DI.


So we will be doing DI for the below types from our UI layer itself.


<IBusinessLayer, CBusinessLayer>

<IDataAccessLayer, CDataAccessLayer> 

Let’s create a .NET Core 3.1 Console application,

Update the Main() method as below,

static void Main(string[] args)
        {
            var services = new ServiceCollection();
            ConfigureServices(services);
            using (ServiceProvider serviceProvider 
                   = services.BuildServiceProvider())
            {
             MyApplication app = serviceProvider.GetService<MyApplication>();
             app.Run();
            }
        }

Add ConfigureServices() method as below,

Using Dependency Injection in a NET Core Console Desktop Application

Please add below NuGet packages explicitly to your application,

  • Microsoft.Extensions.DependencyInjection
  • Microsoft.Extensions.Logging
  • Microsoft.Extensions.Logging.Console

Here we are explicitly injecting types like,

  • MyApplication,
  • CBusinessLayer
  • CDataAccessLayer
  • ILogger

Lifetime management of these types will be based on they are configured through service collection. Like singleton or scoped service behavior etc.

Here is the complete code for the Program.cs

class Program
    {
    static void Main(string[] args)
        {
            var services = new ServiceCollection();
            ConfigureServices(services);
            using (ServiceProvider serviceProvider = 
                                   services.BuildServiceProvider())
            {
             MyApplication app = serviceProvider.GetService<MyApplication>();
             app.Run();
            }
        }

    private static void ConfigureServices(ServiceCollection services)
        {
            services.AddLogging(configure => configure.AddConsole())
                    .AddTransient<MyApplication>()
                    .AddScoped<IBusinessLayer, CBusinessLayer>()
                    .AddSingleton<IDataAccessLayer, CDataAccessLayer>();

        }
  }

The business layer code is as below,

public class CBusinessLayer : IBusinessLayer
    {
        private readonly ILogger _logger;
        private readonly IDataAccessLayer _dataAccess;

        public CBusinessLayer(ILogger<CBusinessLayer> logger,
                              IDataAccessLayer dataAccess)
        { 
        
            _logger = logger;
            _dataAccess = dataAccess;
        }

        public IDataAccessLayer DataAccess => _dataAccess;

        public void PerformBusiness()
        {
            _logger.LogInformation("BusinessLayer {BusinessLayerEvent} at {dateTime}", "Started", DateTime.UtcNow);

            // Perform Business Logic here 
            _dataAccess.Create();

            _logger.LogInformation("BusinessLayer {BusinessLayerEvent} at {dateTime}", "Ended", DateTime.UtcNow);

        }
    } 

Once you execute the application here is the output execution with logging on the console,

Using a similar concept I have implemented Logging in a Console application. Please visit the below post for more details.

Implement DI using Generic HostBuilder

Dependency injection can be implemented using generic HostBuilder in a .NET Core console application. Please see the below article for more details,

Summary

Today we learned how to leverage the Dependency Injection (DI) principle in Console apps or Desktop apps types of NET Core applications.

We understood unlike ASP.NET Core-based applications like MVC or WebAPI apps, the .NET Core Console application doesn’t have dependency injection inbuilt framework. It also doesn’t have a pipeline preconfigured but with a few custom changes and best practices as mentioned above, we can very much achieve similar functionality and can create lightweight, maintainable, and performative Console applications.

Hope you liked this article! Please sound off your comments below.



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.