facebook

Blog

Stay updated

How to use the dependency injection in a .Net Core console application to manage logging with Serilog
To log-in or not to log-in? No problem!
Tuesday, March 12, 2019

Among the many innovations introduced in ASP.NET Core, one of the most important is the existence of an incorporated “Dependency injection” motor.

The Visual Studio for a project ASP.NET Core MVC includes the configuration needed to use it, whereas we don’t have any kind of help, when we create a console application .NET Core.

We investigate now how to solve this problem. As first step, we create two interfaces in our project.

In this demo I used the .NET Core version 2.2.

namespace DemoArticolo.Interfaces
{
 
    public interface InterfaceA
    {
        void DoSomething();
    }
 
    public interface InterfaceB
    {
        void DoSomethingElse();
    }
}

We create then two classes, that will implement these interfaces.

public class ClassA : InterfaceA
{
    public void DoSomething()
    {
       Console.WriteLine("Writing something to the console from ClassA");
    } 
}

In the class constructor of the ClassB, the interface interfaceA has been injected.

Now we have to install the following packet through NuGet: Microsoft.Extensions.DependencyInjection

We need now a method that add and possibly configure our services.

private static void ConfigureServices(ServiceCollection serviceCollection)
{
           serviceCollection.AddSingleton<InterfaceA, ClassA>();
           serviceCollection.AddSingleton<InterfaceB, ClassB>();
}

We choose the AddSingleton() method, which use always the same ClassA and ClassB Instance for every request.

It is also possible to operate different choices: AddScoped() or AddTransient() for example, depending on the context where you are writing the code. The complete documentation is available at following address

The ConfigureServices() method is invoked in the Main() method of our console application, in order to create a ServiceCollection, that we will use in the application.

We need to develop a ServiceProvider, that is to say the object able to recover the instances of our services:

static void Main(string[] args)
{
    var serviceCollection = new ServiceCollection();
    ConfigureServices(serviceCollection);
 
    var serviceProvider = serviceCollection.BuildServiceProvider();
}

At this stage, we just need to use instances of our services:

static void Main(string[] args)
{
    var serviceCollection = new ServiceCollection();
    ConfigureServices(serviceCollection);
 
    var serviceProvider = serviceCollection.BuildServiceProvider();
    var implementazione = serviceProvider.GetService<InterfaceB>();
    implementazione.DoSomethingElse();
}

A more concrete example of this technique is that of Logging in .NET Core, an API that is compatible with a lot of third-party logging provider.

We need to install two more NuGet packets:Microsoft.Extensions.Logging and Microsoft.Extensions.Logging.Console

We modify the ConfigureService method to register a Logging service through console.

private static void ConfigureServices(ServiceCollection serviceCollection)
{
   serviceCollection.AddSingleton<InterfaceA, ClassA>();
   serviceCollection.AddSingleton<InterfaceB, ClassB>();
   serviceCollection.AddLogging(configure => configure.AddConsole());
}

We modify the ClassB by injecting the Logging service through the constructor.

public class ClassB : InterfaceB
{
    private readonly InterfaceA interfaceA;
    private readonly ILogger<Program> logger;
 
    public ClassB(InterfaceA _interfaceA, ILogger<Program> _logger)
    {
        interfaceA = _interfaceA;
        logger = _logger;
    }
    public void DoSomethingElse()
    {        
        interfaceA.DoSomething();
        logger.LogInformation("Logging from InterfaceB");
    }
}

We modify then the method Main() to display the logging effect in the terminal:

static void Main(string[] args)
{
    var serviceCollection = new ServiceCollection();
    ConfigureServices(serviceCollection);
 
    var serviceProvider = serviceCollection.BuildServiceProvider();
 
    var logger = serviceProvider.GetService<ILogger<Program>>();
    logger.LogWarning("Hello, Dependency");
 
    var implementazione = serviceProvider.GetService<InterfaceB>();
    implementazione.DoSomethingElse();
 
    Console.ReadLine();
}

As last example, we use Serilog, a very common logging library, which is compatible both with .NET and .NET Core. Packets to install are:

We modify now the method ConfigureServices, in order to regiter Serilog. We initially choose to run the log only on console.

private static void ConfigureServices(ServiceCollection serviceCollection)
{
    Log.Logger = new LoggerConfiguration()
     .Enrich.FromLogContext()
     .WriteTo.Console()
     .CreateLogger();
 
    serviceCollection.AddSingleton<InterfaceA, ClassA>();
    serviceCollection.AddSingleton<InterfaceB, ClassB>();
    // serviceCollection.AddLogging(configure => configure.AddConsole());
 
    serviceCollection.AddLogging(configure => configure.AddSerilog());
}

The output has been modified (and remember that you can configure it further).

We can display log messages in the console and in the same time save them on file. The modification of CongifureServices () is very simple.

private static void ConfigureServices(ServiceCollection serviceCollection)
{
    Log.Logger = new LoggerConfiguration()
     .Enrich.FromLogContext()
     .WriteTo.Console()
     .WriteTo.File("log.txt", rollingInterval: RollingInterval.Day)
     .CreateLogger();
 
    serviceCollection.AddSingleton<InterfaceA, ClassA>();
    serviceCollection.AddSingleton<InterfaceB, ClassB>();
    // serviceCollection.AddLogging(configure => configure.AddConsole());
 
    serviceCollection.AddLogging(configure => configure.AddSerilog());
}

There are many other packets, that manage the Serilog logging. These packets are defined as Sink. You can find the complete list of sink available for Serilog at this address .

The code used in this article is available on GitHub at following link