it-roy-ru.com

Использование Asp.Net Core 2 Injection для Serilog с несколькими проектами

У меня настроен Serilog для Asp.Net Core 2.0, и он отлично работает с помощью внедрения зависимостей .Net Core в мой стартовый веб-проект (если я использую его через Microsoft.Extensions.Logging), но я не могу получить к нему доступ из любого другого проекта.

Вот что у меня есть:

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

Запуск .cs по умолчанию. Я никак не изменил его по сравнению с оригинальным шаблоном для нового проекта Asp.Net Core MVC.

Я подумал, что мне может понадобиться добавить Serilog в сервисах IServiceCollection, но статья Leaner, более подлая регистрация в ASP.NET Core 2 на https://nblumhardt.com/2017/08/use- serilog/ говорит мне, что это не нужно.

Затем вы можете продолжить и удалить любую другую конфигурацию регистратора торчать вокруг: нет необходимости в разделе «Ведение журнала» в appsettings.json, нигде нет AddLogging () и нет конфигурации через ILoggerFactory в Startup.cs.

UseSerilog () заменяет встроенный ILoggerFactory, чтобы каждый логгер в вашем приложении, будь то класс журнала Serilog, класс Serilog ILogger или Microsoft.Extensions.Logging.ILogger будут поддерживаться с той же реализацией Serilog, и управляется через тот же конфигурации.

Что я ожидал

Возможность просто внедрить регистратор через конструктор в любом классе в любом проекте в решении. Например:

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

What I Got - веб (стартовый) проект

Инжекция работает в HomeController, если я использую оболочку Microsoft.Extensions.Logging:

using Microsoft.Extensions.Logging;

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

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

Внедрение не выполняется в любом проекте/классе, если я пытаюсь внедрить 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: невозможно разрешить службу для типа 'Serilog.ILogger' при попытке активации 'ObApp2.Web.Mvc.Controllers.HomeController.

Моя большая проблема - другие проекты

Моя большая проблема в том, что я не могу получить регистратор через DI ни одним из методов, которые я пробовал, если я работаю в другом проекте в решении.

Когда я пытаюсь внедрить либо используя Microsoft.Extensions.Logging или Serilog, я получаю исключение отсутствующего параметра во время сборки.

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

- or -

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

Оба генерируют ошибку сборки, похожую на:

Нет аргумента, который соответствует требуемому формальному параметр 'logger' из 'MyTestClass.MyTestClass (ILogger)'

Вопросы

  1. При внедрении с этим типом конфигурации Serilog рекомендуется ли ссылаться на Microsoft.Extensions.Logging или Serilog в файлах классов, где я делаю инъекцию?

  2. Как я могу заставить DI работать через все проекты?

10
platypusjh

Один метод, который работал для меня:

Я добавил экземпляр Serilog.Core.Logger, используя метод AddSingleton () в методе ConfigureServices. Это решило проблему DI. Этот шаг заменяет шаг назначения экземпляра Logger Log.Logger в конструкторе StartUp.

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

Также измените ссылки в ваших файлах классов, чтобы они указывали на Serilog.Ilogger

4
Rufus Lobo

Это решение правильно внедряет регистратор в классы во внешнем проекте или библиотеке.

Я также попробовал ответ, предложенный Руфусом. У меня не было проблемы, описанной OP, но у меня была еще более странная проблема: после внедрения ILogger во внешний проект регистрация в MS SQL перестала работать. Консольная регистрация работала. Поскольку Serilog - это, в основном, статический сервис, я понял, что следует рассматривать Log.Logger как фабрику. Преимущество заключается в том, что вы по-прежнему можете настраивать ссылки ILogger (например, добавляя ForContext в конструктор), не затрагивая службу «singleton».

Я опубликовал полностью рабочее решение на github включая консольную программу, которая устанавливает DI (будет работать так же с ASP.NET Core), внешнюю библиотеку, которая содержит демонстрацию Serilog для начинающих с делением на ноль и еще одна библиотека, которая управляет Serilog как сервисом. 

Важная часть, регистрация службы Serilog, выглядит следующим образом (и в качестве бонуса мы привязываемся к ProcessExit для прозрачной очистки):

using Microsoft.Extensions.DependencyInjection;
using System;

namespace Serilog.Injection
{
    public static class RegisterSerilogServices
    {
        public static IServiceCollection AddSerilogServices(this IServiceCollection services)
        {
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Verbose()
                .WriteTo.Console()
                .WriteTo.MSSqlServer(@"xxxxxxxxxxxxx", "Logs")
                .CreateLogger();

            AppDomain.CurrentDomain.ProcessExit += (s, e) => Log.CloseAndFlush();

            return services.AddSingleton(Log.Logger);
        }
    }
}
3
McGuireV10

Вы не получаете доступ к Serilog через DI в Net Core. Это статика. Правильно настроив и инициализировав Logger в вашей Program.Main (), просто получите доступ к любому другому статическому элементу в вашем Startup, Controller и т.д., Т.е. 

public void ConfigureServices(IServiceCollection services)
            {
    Serilog.Log.Information("here I am in startup");
    //further options
};

или добавьте вверху:

using static Serilog.Log;

и просто:

Information("keystroke saving"); 

1
gorytus