Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Asp.Net Core 2 Injection for Serilog with Multiple Projects

I have Serilog configured for Asp.Net Core 2.0 and it works great via .Net Core dependency injection in my startup web project (if I use it through Microsoft.Extensions.Logging), but I can't access it from any other project.

Here's what I have:

Program.cs

using System;
using System.IO;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Serilog;

namespace ObApp.Web.Mvc
{
    public class Program
    {
        public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
            .Build();

        public static void Main(string[] args)
        {
            Log.Logger = new LoggerConfiguration()
                .ReadFrom.Configuration(Configuration)
                .CreateLogger();

            try
            {
                Log.Warning("Starting BuildWebHost");

                BuildWebHost(args).Run();
            }
            catch (Exception ex)
            {
                Log.Fatal(ex, "Host terminated unexpectedly");
            }
            finally
            {
                Log.CloseAndFlush();
            }
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .UseSerilog()
                .Build();
    }
}

Startup.cs

Startup .cs is pure default. I haven't altered it in any way from the original template for the new Asp.Net Core MVC project.

I have thought that I might need to add Serilog in the IServiceCollection services, but the article Leaner, meaner ASP.NET Core 2 logging at https://nblumhardt.com/2017/08/use-serilog/ tells me it's unnecessary.

You can then go ahead and delete any other logger configuration that’s hanging around: there’s no need for a "Logging" section in appsettings.json, no AddLogging() anywhere, and no configuration through ILoggerFactory in Startup.cs.

UseSerilog() replaces the built-in ILoggerFactory so that every logger in your application, whether it’s Serilog’s Log class, Serilog’s ILogger, or Microsoft.Extensions.Logging.ILogger, will be backed with the same Serilog implementation, and controlled through the same configuration.

What I Expected

The ability to simply inject a logger via a constructor in any class in any project in the solution. For example:

using Serilog;
public MyTestClass(ILogger logger) { ... }

What I Got - Web (Startup) Project

Injection works in the HomeController if I use the Microsoft.Extensions.Logging wrapper:

using Microsoft.Extensions.Logging;

public class HomeController : Controller
{
    ILogger<HomeController> _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
        _logger.LogDebug("Controller instantiated.");
    }
}

Injection fails in any project/class if I try to inject Serilog.ILogger

using Serilog;
using Serilog.Extensions.Logging; // Not sure if this would help.

public class HomeController : Controller
{
    ILogger _logger;

    public HomeController(ILogger logger)
    {
        _logger = logger;
        _logger.Debug("Controller instantiated.");
    }
}

InvalidOperationException: Unable to resolve service for type 'Serilog.ILogger' while attempting to activate 'ObApp2.Web.Mvc.Controllers.HomeController'.

My Bigger Issue - OtherProjects

My bigger issue is that I can't get a logger via DI through any method I've tried if I'm working in another project in the solution.

When I try to inject either using Microsoft.Extensions.Logging or using Serilog I get a missing parameter exception at build time.

using Microsoft.Extensions.Logging;
namespace ObApp.Domain
{
    public class MyTestClass(ILogger<MyTestClass> logger) { ... }

- or -

using Serilog;
namespace ObApp.Domain
{
    public class MyTestClass(ILogger logger) { ... }

Both generate build error similar to:

There is no argument given that corresponds to the required formal parameter 'logger' of 'MyTestClass.MyTestClass(ILogger)'

Questions

  1. When injecting with this type of Serilog configuration, is it recommended that I reference Microsoft.Extensions.Logging or Serilog in the class files where I'm doing the injection?

  2. How can I get DI to work through all projects?

like image 604
platypusjh Avatar asked Dec 07 '17 19:12

platypusjh


People also ask

Does Serilog use ILogger?

Unlike other logging libraries, Serilog is built with powerful structured event data in mind. Let's set up Serilog as Logging Provider in the native logging system in . NET so you can use the Microsoft ILogger interface.

Does Serilog support .NET core?

Since Serilog supports ASP.NET Cores default logging APIs it can receive log events from ASP.NET Core framework libraries as well. Serilog in ASP.NET Core is very easy to set up and integrate. Serilog provides a structured logging framework and supports a wide variety of sinks to log to console, files, azure, etc.

What is the difference between ILogger and ILoggerFactory?

ILogger: is responsible to write a log message of a given Log Level. ILoggerFactory: you can register one or more ILoggerProvider s with the factory, which in turn uses all of them to create an instance of ILogger . ILoggerFactory holds a collection of ILoggerProviders .


1 Answers

One method that worked for me:

I added an instance of Serilog.Core.Logger using the AddSingleton() method in the ConfigureServices method. This resolved the DI issue. This step replaces the step of assigning a Logger instance to Log.Logger in the StartUp constructor.

services.AddSingleton((ILogger)new LoggerConfiguration()
            .MinimumLevel.Information()
            .WriteTo.File(<...>)
            .CreateLogger());

Also change references in your class files to point to Serilog.Ilogger

like image 64
Rufus Lobo Avatar answered Oct 13 '22 09:10

Rufus Lobo