[英]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.