使用Microsoft的默认设置,使用ILogger<Worker>
注入记录器,如下所示(直接从文档中)
public sealed class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
public Worker(ILogger<Worker> logger) =>
_logger = logger;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.UtcNow);
await Task.Delay(1_000, stoppingToken);
}
}
}
与直接使用ILogger
相比,这种模式提供了什么好处(我认为除了记录器的名称之外)?-或者我们失去了什么,使用ILogger
没有通用部分ILogger<Worker>
我相信还有一些细微的分歧和分歧没有在这里解决https://github.com/dotnet/runtime/issues/48473但还有更多吗?
ILogger
是Microsoft和其他第三方日志库(如Serilog)使用的历史接口,用于抽象日志记录器,防止开发人员将其应用程序代码耦合到单个库。这允许应用程序开发人员在需要时更改他们的日志库。
ILogger<T>
继承自ILogger
,是Microsoft对日志记录器的新抽象。泛型可以防止DI引擎中的冲突。还要注意的是,从。net 6开始,微软的日志库不再注册ILogger
。这意味着你需要将ILogger<T>
注入到你的服务中。
其他库可能还没有进行更新,您可能仍然需要注入ILogger
对象才能使它们工作。请参阅库文档。如果您需要兼容性,您可以手动注册ILogger
,并在注入中继续使用ILogger
。
还要注意,你可以在注入后删除泛型部分:
public sealed class Worker : BackgroundService
{
private readonly ILogger _logger;
public Worker(ILogger<Worker> logger) => _logger = logger; // implicit cast
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.UtcNow);
await Task.Delay(1_000, stoppingToken);
}
}
}
虽然不能使用标准的MS DI方法直接通过actor注入ILogger
,但是有一种方法可以做到。
只需将EgonsoftHU.Extensions.Logging.Autofac nuget包添加到您的启动项目中,并按如下方式修改您的Program.cs
文件:
using Autofac;
using Autofac.Extensions.DependencyInjection;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder
.Host
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureContainer<ContainerBuilder>(
containerBuilder =>
containerBuilder.RegisterModule<EgonsoftHU.Extensions.Logging.Autofac.DependencyModule>();
);
你可以使用MS DI方法保留现有的依赖项注册,它们将由AutofacServiceProvider
而不是Microsoft.Extensions.DependencyInjection.ServiceProvider
解决。两者都实现相同的IServiceProvider
接口。
现在可以注入ILogger
而不是ILogger<T>
。
using Microsoft.Extensions.Logging;
public class Service
{
private readonly ILogger logger;
public Service(ILogger logger)
{
this.logger = logger;
}
}
当然,您可能会问,是否值得为此添加一个nuget包。
MS DI方法可能涵盖基本用例,但Autofac有高级用例的解决方案。
。在示例代码中注册的模块将自定义中间件添加到Autofac的解析管道中。这个中间件只是通过一个额外的参数扩展了参数列表,这样当需要解析一个ILogger
参数时,它就会用参数的声明类型解析通用的ILogger<>
类型。看到这里。
请注意:
您仍然无法直接使用IServiceProvider
的扩展方法来解析ILogger
实例,例如GetService<T>()
或GetRequiredService<T>()
。相反,您可以使用ILoggerFactory.CreateLogger(string)
方法。
或者您可以将ILoggerFactory
注入到该函数中,并在其中创建日志记录器。
using Microsoft.Extensions.Logging;
public class Service
{
private readonly ILogger logger;
public Service(ILoggerFactory loggerFactory)
{
logger = loggerFactory.CreateLogger(GetType());
}
}
您的问题的答案可以在文档本身中找到:日志类别标题下的最后一行。从那里复制:
ILogger<T>
相当于用T
的完全限定类型名调用CreateLogger
。