簡體   English   中英

簡單注入器:注冊 ILogger<T> 通過使用 ILoggerFactory.CreateLogger<T> ()

[英]Simple Injector: Register ILogger<T> by using ILoggerFactory.CreateLogger<T>()

我正在使用一個使用 Simple Injector 作為依賴注入器的項目。 另一方面,該項目使用 Microsoft.Extensions.Logging 來記錄某些類中發生的事件。

我的技術問題很容易解釋。 我想在我的 DI 中注冊獨立於被調用的類 T 的 ILogger,但確實需要從我的ILoggerFactory.CreateLogger<T>()方法中完成它,因為這使用Microsoft.Extensions.Configuration獲取記錄器配置。

我需要使用這樣的東西來實例我的記錄器:

private Microsoft.Extensions.Logging.ILogger CreateLogger<T>()
{
     var factory = this.ResolveService<ILoggerFactory>();
     var logger = factory.CreateLogger<T>();
     return logger;
}

我可以通過執行以下操作來實現注入:

Container.Register(typeof(ILogger<>), typeof(Logger<>));

這使我們能夠解決以下問題:

public class SomeApiController : ApiController
{
     public SomeApiController(ILogger<SomeApiController> logger)
     {
         //logger is well instantiated, but doesn't got the configuration
         logger.LogInformation("test log.");
     }
}

但正如我所說,這樣做沒有通過從Microsoft.Extensions.Logging.ILoggerFactory類獲得的配置,所以這沒有用。

有沒有辦法使用我的CreateLogger<T>注冊ILogger<T> CreateLogger<T>

使用以下注冊:

container.RegisterInstance<ILoggerFactory>(loggerFactory);
container.RegisterSingleton(typeof(ILogger<>), typeof(Logger<>));

或者,如果您要將Simple Injector 集成到通用主機或 ASP.NET Core 應用程序中,請使用.AddLogging()擴展方法甚至將非通用ILogger注入您的應用程序組件,如本 ASP.NET 中所示核心Startup類:

public class Startup
{
    ...

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddLogging(); // Adds logging to the framework

        // AddSimpleInjector enables "cross wiring," which means you can let
        // Simple Injector-resolved components to depend on the generic
        // ILogger<T> abstraction.
        services.AddSimpleInjector(container, options =>
        {
            options.AddAspNetCore();
            
            // AddLogger allows Simple Injector-resolved components to depend on 
            // the non-generic Microsoft.Extensions.Logging.ILogger interface.
            // Simple Injector will automatically inject the correct ILogger<T>
            // for you.
            options.AddLogging();
        });
    }

    ...
}

有關完整示例,請參閱ASP.NET Core 和 ASP.NET Core MVC 集成指南

讓應用程序組件依賴ILogger而不是ILogger<T> ,可以使您的代碼更簡單、更易於測試且不易出錯。 如果您使用沒有服務集合集成的Simple Injector(如前面的示例所示,您可以使用以下注冊讓 Simple Injector 確保在注入ILogger時仍然注入正確的Logger<T>

container.RegisterConditional(
    typeof(ILogger),
    c => typeof(Logger<>).MakeGenericType(c.Consumer.ImplementationType),
    Lifestyle.Singleton,
    _ => true);

這確保每個應用程序組件都有自己的Logger<T>實例,其中T是記錄器注入的組件的類型。 以以下依賴ILogger類為例:

public class ComponentA : IService
{
    public ComponentA(ILogger logger) { ... }
}

上述注冊將確保ComponentA注入Logger<ComponentA> ,即使它僅依賴於ILogger而不是ILogger<T>

如果以上內容滿足您的需求,您可以在此處停止閱讀……或者如果您對更可靠的解決方案感興趣,請繼續閱讀。

可靠的解決方案

除了讓應用程序組件依賴於框架定義的ILogger抽象之外,您還可以選擇定義特定於應用程序的記錄器抽象,如依賴倒置原則(DIP) 所規定的那樣。

DIP 聲明抽象應該由應用程序本身定義 - 這意味着您定義自己的記錄器抽象(另請參閱this以了解您為什么要這樣做)並在此基礎上構建一個適配器,很像這里描述的那樣. 您可以簡單地從所描述的MicrosoftLoggingAdapter派生您的通用適配器,如下所示:

public sealed class MicrosoftLoggingAdapter<T> : MicrosoftLoggingAdapter 
{
    public MicrosoftLoggingAdapter(ILoggerFactory factory) 
        : base(factory.CreateLogger<T>()) { }
}

使用這個通用適配器,您可以按如下方式配置 Simple Injector:

container.RegisterInstance<ILoggerFactory>(factory);

container.RegisterConditional(
    typeof(MyApplication.Abstractions.ILogger),
    c => typeof(MicrosoftLoggingAdapter<>).MakeGenericType(c.Consumer.ImplementationType),
    Lifestyle.Singleton,
    _ => true);

基於史蒂文的解決方案,我發布了我的答案以幫助其他人:

    private void RegisterServices()
    {
        Container.Register(ConfigureLogger, Lifestyle.Singleton);            
        Container.Register(typeof(ILogger<>), typeof(LoggingAdapter<>));
    }

    private ILoggerFactory ConfigureLogger()
    {
        LoggerFactory factory = new LoggerFactory();

        var config = new ConfigurationBuilder()
            .AddJsonFile("logging.json")
            .Build();

        //serilog provider configuration
        var log = new LoggerConfiguration()
                 //.ReadFrom.Configuration(config)
                 .WriteTo
                 .RollingFile(ConfigSettings.LogsPath)
                 .CreateLogger();

        factory.AddSerilog(log);

        return factory;
    }

    public class LoggingAdapter<T> : ILogger<T>
    {
        private readonly Microsoft.Extensions.Logging.ILogger adaptee;          

        public LoggingAdapter(ILoggerFactory factory)
        {
            adaptee = factory.CreateLogger<T>();
        }

        public IDisposable BeginScope<TState>(TState state)
        {
            return adaptee.BeginScope(state);
        }

        public bool IsEnabled(LogLevel logLevel)
        {
            return adaptee.IsEnabled(logLevel);
        }

        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {
            adaptee.Log(logLevel, eventId, state, exception, formatter);
        }
    }   

如您所見,我的解決方案使用 Serilog 作為提供程序來登錄Microsoft.Extensions.Logging

希望能幫助到你!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM