为什么 .NET Core DI 容器不注入 ILogger?

msc*_*cho 10 c# logging dependency-injection .net-core

我正在尝试在基于 .NET Core 2.1 的 C# 控制台应用程序中登录并运行。

我在 DI 声明中添加了以下代码:

var sc = new ServiceCollection();

sc.AddLogging(builder =>
{
    builder.AddFilter("Microsoft", LogLevel.Warning);
    builder.AddFilter("System", LogLevel.Warning);
    builder.AddFilter("Program", LogLevel.Warning);
    builder.AddConsole();
    builder.AddEventLog();
});
Run Code Online (Sandbox Code Playgroud)

我试图通过在服务Microsoft.Extensions.Logging.ILogger的构造函数中使用接口来注入服务,但出现以下错误:

未处理的异常:System.InvalidOperationException:尝试激活“MyService”时无法解析“Microsoft.Extensions.Logging.ILogger”类型的服务。

    at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
    at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain)
    at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot)
    at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Type serviceType, CallSiteChain callSiteChain)
    at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
    at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
    at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
    at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain)
    at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot)
    at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateEnumerable(Type serviceType, CallSiteChain callSiteChain)
    at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
    at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
    at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.CreateServiceAccessor(Type serviceType)
    at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
    at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
    at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
    at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
    at Program.Main(String[] args) in Program.cs:line 27
Run Code Online (Sandbox Code Playgroud)

我在这里误解了什么吗?如果没有AddLogging方法足以暴露在DI容器中的服务?

pin*_*x33 11

依赖注入系统不注册ILogger。相反,它注册ILogger<T>. 如果您需要记录器的实例,则需要接受ILogger<MyService>.

这背后的原因是泛型参数用于构建记录器的类别名称——这是所有记录器都需要的。对于非通用记录器,不一定有一个好的默认名称。如果你真的想要一个非通用的ILogger,你可以注册一个这样的(随意更改名称):

services.AddSingleton(sp => sp.GetRequiredService<ILoggerFactory>().CreateLogger("DefaultLogger"));
Run Code Online (Sandbox Code Playgroud)

或者,您可以ILoggerFactory在构造函数中接受 an ,然后即时创建自己的记录器。


Ste*_*ven 9

为了MS.DI能够从做一个映射ILoggerILogger<T>其中T变成了消费者,它必须支持基于上下文的注入。这意味着在使用 MS.DI 构建应用程序时,您将不得不让您的类依赖于ILogger<T>.

MS.DI 缺少此功能的原因有多种。我认为最重要的两个原因是:

  • MS.DI 仅实现框架组件本身所需的功能。请记住:MS.DI 是专门为 ASP.NET Core 框架、其组件及其第三方构建和设计的。远不是一个成熟的 DI 容器
  • MS.DI 尝试成为最低公分母(LCD),它尝试仅支持所有其他 DI 容器也支持的功能,以允许您用更成熟、功能丰富的 DI 容器替换此内置容器。

我理解你的烦恼。很高兴看到 MS.DI 支持基于上下文的注入,因为依赖于ILogger应用程序组件很有意义,因为这使您的代码更简单、更易于测试且不易出错。

不幸的是,由于 MS.DI 的设计和它的 LCD 理念,它不太可能获得这样的功能。每次 Microsoft 添加行为时,都会与大多数 DI 容器的维护者进行长时间而复杂的讨论,以了解如何以与所有其他库兼容的方式支持此类功能(我自己也参与了许多此类讨论) . 这是一项艰巨的任务,并且在某些情况下已被证明是不可能的。

相反,选择包含此类功能和许多其他功能的更成熟且功能丰富的 DI 容器是有意义的。例如,对于Simple Injector,我们 添加了用于注入的集成ILogger。但是还有其他 DI 容器允许您注入ILogger.