【问题标题】:Why does .NET Core DI container not inject ILogger?为什么.NET Core DI 容器不注入 ILogger?
【发布时间】:2020-09-20 16:44:08
【问题描述】:

我正在尝试在基于 .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();
});

我尝试在服务的构造函数中使用接口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

我在这里误解了什么吗? AddLogging方法不应该足以暴露DI容器中的Service吗?

【问题讨论】:

    标签: c# logging .net-core dependency-injection


    【解决方案1】:

    依赖注入系统没有注册ILogger。相反,它注册ILogger<T>。如果你需要一个记录器的实例,你需要接受ILogger<MyService>

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

    services.AddSingleton(sp => sp.GetRequiredService<ILoggerFactory>().CreateLogger("DefaultLogger"));
    

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

    【讨论】:

    • "对于非通用记录器,不一定有一个好的默认名称。"这不一定是真的,因为在大多数情况下,名称是从消费者的名称派生的,这就是通过将ILogger&lt;MyService&gt; 注入MyService 来实现的。大多数 DI 容器实际上允许您进行这样的配置(除了 MS.DI)。这种做法通常被称为“基于上下文的注入”。
    • 我的意思是基于 MS 的 DI,它不能/不能为上下文创建类别名称
    【解决方案2】:

    为了让 MS.DI 能够进行从 ILoggerILogger&lt;T&gt; 的映射,T 成为消费者,它必须支持基于上下文的注入。这意味着在使用 MS.DI 构建应用程序时,您必须让您的类依赖于 ILogger&lt;T&gt;

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

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

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

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

    相反,选择一个更成熟且功能丰富的 DI Container 是有意义的,它包含此类功能以及许多其他功能。对于Simple Injector,例如,我们added integration 用于注入ILogger。但是还有其他 DI 容器允许您注入 ILogger

    【讨论】:

      猜你喜欢
      • 2016-11-10
      • 2020-08-08
      • 1970-01-01
      • 1970-01-01
      • 2015-08-21
      • 2022-01-11
      • 2018-03-13
      • 2010-09-18
      • 1970-01-01
      相关资源
      最近更新 更多