这可能在某种程度上与Pass ILogger or ILoggerFactory to constructors in AspNet Core?有关,但是这具体是关于Library Design,而不是关于使用这些库的实际应用程序如何实现其日志(log)记录.

我正在写一篇文章.net标准2.0库将通过Nuget安装,为了让使用该库的人获得一些调试信息,我依靠Microsoft.Extensions.Logging.Abstractions来允许注入标准化的记录器.

然而,我看到了多个接口,web上的示例代码有时会使用ILoggerFactory,并在类的ctor中创建一个记录器.还有ILoggerProvider,它看起来像工厂的只读版本,但实现可能实现,也可能不实现这两个接口,所以我不得不 Select .(工厂似乎比供应商更常见).

我看到的一些代码使用非泛型ILogger接口,甚至可能共享同一个记录器的一个实例,一些代码在其ctor中使用ILogger<T>,并期望DI容器支持开放泛型类型或显式注册库使用的每个ILogger<T>变体.

现在,我确实认为ILogger<T>是正确的方法,可能是一个不接受那个参数,只传递一个空记录器的ctor.这样,如果不需要日志(log)记录,则不使用日志(log)记录.然而,一些DI容器 Select 了最大的ctor,因此无论如何都会失败.

我很好奇我会在这里做些什么来给用户带来最少的麻烦,同时仍然允许适当的日志(log)支持(如果需要的话).

推荐答案

释义

我们有3个接口:ILoggerILoggerProviderILoggerFactory.让我们来看看这source code人,看看他们的责任:

ILogger:负责编写给定Log Level的日志(log)消息.

ILoggerProvider:负责创建ILogger的实例(您不应该直接使用ILoggerProvider来创建记录器)

ILoggerFactory:您可以向工厂注册一个或多个ILoggerProvider,工厂反过来使用所有ILoggerProvider来创建ILogger的实例.ILoggerFactoryCollection 了ILoggerProviders本书.

在下面的示例中,我们向工厂注册了两个Provider (控制台和文件).当我们创建一个记录器时,工厂使用这两个提供程序来创建Logger的实例:

ILoggerFactory factory = new LoggerFactory().AddConsole();    // add console provider
factory.AddProvider(new LoggerFileProvider("c:\\log.txt"));   // add file provider
Logger logger = factory.CreateLogger(); // <-- creates a console logger and a file logger

因此,记录器本身正在维护一个ILoggers的集合,并将日志(log)消息写入所有ILoggers.Looking at Logger source code我们可以确认Logger有一个ILoggers(即LoggerInformation[])的数组,同时它正在实现ILogger接口.


依赖项注入

MS documentation提供了两种注入记录器的方法:

1. Injecting the factory:

public TodoController(ITodoRepository todoRepository, ILoggerFactory logger)
{
    _todoRepository = todoRepository;
    _logger = logger.CreateLogger("TodoApi.Controllers.TodoController");
}

creates a Logger with Category = TodoApi.Controllers.TodoController

2. Injecting a generic 100:

public TodoController(ITodoRepository todoRepository, ILogger<TodoController> logger)
{
    _todoRepository = todoRepository;
    _logger = logger;
}

creates a logger with Category = fully qualified type name of TodoController


在我看来,让文档混乱的是,它没有提到任何关于注入非通用的ILogger.在上面的同一个例子中,我们正在注入一个非通用的ITodoRepository,但它并不能解释为什么我们没有对ILogger进行同样的操作.

根据Mark Seemann:

注入构造函数只需接收

将工厂注入控制器不是一个好方法,因为初始化记录器不是控制器的责任(违反SRP).同时,注入通用ILogger<T>会增加不必要的噪音.详见Simple Injector's博客:What’s wrong with the ASP.NET Core DI abstraction?

应该注入的(至少根据上面的文章)是非通用的ILogger,但这不是微软内置的DI容器所能做到的,你需要使用第三方DI库.These two个文档解释了如何使用第三方库.净核心.


这是尼古拉·马洛维奇的another article页,他在其中解释了国际奥委会的5条规则.

Nikola’s 4th law of IoC

正在解析的类的每个构造函数都不应该有

.net相关问答推荐

将Visual Studio更新到v17.9.3后,IDE关闭,dotnet.exe命令报告致命错误.内部CLR错误.(0x80131506)

.NET发布的应用程序运行与开发不同的端口

跨请求共享数据

在数据网格中:如何在更改单元格 A 中的值后显示单元格 B 中的更改

如何在 NET 5 / 6 中使用 Direct3D11CaptureFramePool

使属性只能通过绑定的 Editor(component) 编辑

为什么 StyleCop 建议在方法或属性调用前加上this?

在一个 LINQ 查询中获取两列的总和

Style 和 ControlTemplate 的区别

大型 WCF Web 服务请求因 (400) HTTP 错误请求而失败

什么是 SUT,它来自哪里?

哪个更快:清除集合或实例化新的

CryptographicException 未处理:系统找不到指定的文件

您可以使用 Xamarin 开发 Linux 应用程序吗?

找不到库 hostpolicy.dll

合并两个(或更多)PDF

为什么要使用 C# 类 System.Random 而不是 System.Security.Cryptography.RandomNumberGenerator?

为 webClient.DownloadFile() 设置超时

在foreach循环中修改列表的最佳方法是什么?

System.ServiceModel 在 .NET Core 项目中找不到