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