【发布时间】:2017-11-15 05:06:47
【问题描述】:
在 asp.net core 1.1 中,我可以将 IServiceProvider 注入记录器提供程序并在调用 CreateLogger 时解析我的记录器,但在 asp.net core 2.0 中这一切都发生了变化
我的 ILogger 实现需要注入依赖项。 我怎样才能做到这一点?
【问题讨论】:
标签: c# asp.net-core asp.net-core-2.0
在 asp.net core 1.1 中,我可以将 IServiceProvider 注入记录器提供程序并在调用 CreateLogger 时解析我的记录器,但在 asp.net core 2.0 中这一切都发生了变化
我的 ILogger 实现需要注入依赖项。 我怎样才能做到这一点?
【问题讨论】:
标签: c# asp.net-core asp.net-core-2.0
ASP.NET 核心提供了用自定义容器替换内置 DI 容器的可能性(有关详细信息,请参阅this 文章)。您可以利用这种可能性来更早地获取 IServiceProvider 的实例以记录引导,同时仍使用标准的 .Net 核心 DI 容器。
为此,您应该将 Startup.ConfigureServices(IServiceCollection services) 方法的返回值从 void 更改为 IServiceProvider。您可以使用这种可能性在 ConfigureServices 中构建 IServiceProvider 的实例,将其用于记录引导,然后从方法返回。
示例代码:
public interface ISomeDependency
{
}
public class SomeDependency : ISomeDependency
{
}
public class CustomLogger : ILogger
{
public CustomLogger(ISomeDependency dependency)
{
}
// ...
}
public class CustomLoggerProvider : ILoggerProvider
{
private readonly IServiceProvider serviceProvider;
public CustomLoggerProvider(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public ILogger CreateLogger(string categoryName)
{
return serviceProvider.GetRequiredService<ILogger>();
}
// ...
}
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
return ConfigureLogging(services);
}
private IServiceProvider ConfigureLogging(IServiceCollection services)
{
services.AddTransient<ISomeDependency, SomeDependency>();
services.AddSingleton<ILogger, CustomLogger>();
IServiceProvider serviceProvider = services.BuildServiceProvider();
var loggerFactory = new LoggerFactory();
loggerFactory.AddProvider(new CustomLoggerProvider(serviceProvider));
return serviceProvider;
}
// ...
}
【讨论】:
如果您在 program.cs 中配置日志记录,您可以创建一个函数来配置日志记录并获取日志记录提供程序的实例,如下所示:
private static void ConfigureApplicationLogging(WebHostBuilderContext context, ILoggingBuilder loggingBuilder)
{
loggingBuilder.AddConfiguration(context.Configuration.GetSection("Logging"));
loggingBuilder.AddDebug();
loggingBuilder.AddConsole();
var serviceProvider = loggingBuilder.Services.BuildServiceProvider();
loggingBuilder.AddProvider(new DoxErrorLoggerProvider(serviceProvider, null));
}
然后在 BuildWebHost 中配置日志记录如下:
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging(ConfigureApplicationLogging)
.UseNLog()
.UseStartup<Startup>()
.Build();
【讨论】:
从你在各个地方需要的依赖项开始
public class SomeDependency : ISomeDependency
{
}
一个扩展文件,以便我们可以根据 MSDN 在 ServiceCollection 上配置日志记录 您可以在各种来源中找到非常标准的东西
public static class ApplicationLoggerFactoryExtensions
{
public static ILoggingBuilder CustomLogger(this ILoggingBuilder builder)
{
builder.Services.AddSingleton<ILoggerProvider, CustomLoggerProvider>();
//Be careful here. Singleton may not be OK for multi tenant applications - You can try and use Transient instead.
return builder;
}
}
记录器提供程序是在您处理业务代码并需要记录内容时被称为之后服务的部分。
因此,在应用程序的上下文中,DI 是在此处构建并可用的。现在为什么 ILoggerProvider 存在可能是有道理的。
public class CustomLoggerProvider : ILoggerProvider
{
private ISomeDependency someDependency;
public CustomLoggerProvider(ISomeDependency someDependency)
{
this.someDependency = someDependency;
}
public ILogger CreateLogger(string categoryName)
{
return new CustomeLogger(someDependency);
}
}
具体的自定义记录器非常简单
public class CustomLogger : ILogger
{
public CustomLogger(ISomeDependency dependency)
{
}
}
在您配置 ServiceCollection 的地方.. 就像在 Startup.cs 中的 OP 问题中一样
private void ConfigureServices(IServiceCollection services)
{
services.AddTransient<ISomeDependency, SomeDependency>();
//services.AddSingleton<ILogger, CustomLogger>(); <== NO
var loggerFactory = new LoggerFactory(); //??? newer DotNet gives you LoggerFactory in startup this may be unnecessary.
//Add some console printer
services.AddLogging(configure => configure.AddConsole())
.Configure<LoggerFilterOptions>(options => options.MinLevel = LogLevel.Trace);
//Add our custom logger
services.AddLogging(configure => configure.CustomLogger()); // <== our extension helping out!
}
✘ 不要 - 不要将任何 ILogger 添加到您的服务中
LoggerFactory 和LoggerProvider 配置的全部意义在于简化ILogger 的使用
public MyBusinessService(ILogger<BusinessServiceClass> log)
{
log.Information("Please tell all registered loggers I am logging!);
}
在我的示例中,它将向控制台打印出消息(如果可用)以及采用我们注入的依赖项的 CustomLogger。如果您注册更多..它将转到所有人
【讨论】: