无法从 Microsoft.Extensions.Logging 解析 ILogger

Posted

技术标签:

【中文标题】无法从 Microsoft.Extensions.Logging 解析 ILogger【英文标题】:Unable to resolve ILogger from Microsoft.Extensions.Logging 【发布时间】:2019-03-26 02:13:54 【问题描述】:

我已经像这样配置了我的控制台应用程序的Main

var services = new ServiceCollection()
    .AddLogging(logging => logging.AddConsole())
    .BuildServiceProvider();

然后我尝试在另一个类中使用它

private readonly ILogger _logger;
    
public MyClass(ILogger logger)

    _logger = logger;


public void MyFunc()

    _logger.Log(LogLevel.Error, "My Message");

System.InvalidOperationException: '无法解析服务类型 'Microsoft.Extensions.Logging.ILogger'

我已经尝试了here 的解决方案,但它对我不起作用。

编辑 根据下面 Yaakov 的评论和this Github comment,我可以通过这样做正确解决它

public MyClass(ILogger<MyClass> logger)

    _logger = logger;

我本来希望在最初的 BuildServiceProvider 中有这个,但看起来我每次想使用记录器(或创建我自己的 ILogger)时都必须重复这个。

【问题讨论】:

那么您注册服务集合的部分在哪里? @EmrahSüngü 我不认为我是单独做的。在..AddLogging(logging =&gt; logging.AddConsole()) 之后,我在该链中还有其他解析器,例如正确解析的.AddScoped&lt;IMyInterface, MyMethod&gt;() 如果您尝试解析 ILogger&lt;MyClass&gt; 是否有效? @yaakov 是的,确实如此。但是有没有其他方法可以注册,这样我就不必每次都做public MyClass(ILogger&lt;MyClass&gt; logger) 我不知道。我相信它的设计方式是让 DI 还添加有关从何处记录数据的信息。 【参考方案1】:

ILogger 不再默认注册,但ILogger&lt;T&gt; 是。如果您仍想使用 ILogger,您可以使用以下代码手动注册(Startup.cs):

public void ConfigureServices(IServiceCollection services)

    var serviceProvider = services.BuildServiceProvider();
    var logger = serviceProvider.GetService<ILogger<AnyClass>>();
    services.AddSingleton(typeof(ILogger), logger);
    ...

AnyClass 可以是通用的,例如:

public class ApplicationLogs


所以:

public void ConfigureServices(IServiceCollection services)

    var serviceProvider = services.BuildServiceProvider();
    var logger = serviceProvider.GetService<ILogger<ApplicationLog>>();
    services.AddSingleton(typeof(ILogger), logger);
    ...

ILogger 现在将通过构造函数注入进行解析。

【讨论】:

这被认为是不好的做法(从 ConfigureServices 构建您的服务提供者)。这样,您的所有单例服务都会被实例化两次。 @MathiasLykkegaardLorenzen 包括或指明首选实现会很有帮助。 很确定你应该注册一个瞬态,在运行时解析ILogger&lt;ApplicationLog&gt; 创建中间服务提供者有点阴暗,但这可能是避免它的解决方案:***.com/a/70610564/646942【参考方案2】:

我假设您正在使用 .net 核心 Web 应用程序的默认模板。 在您的 Startup.cs 中,您应该有这样的方法↓↓↓↓↓↓↓

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)

    services.Configure<CookiePolicyOptions>(options =>
        
            // This lambda determines whether user consent for non-essential cookies is needed for a given request.
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        );


        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        //Do the service register here and extra stuff you want
         services.AddLogging(config =>
        
            config.AddDebug();
            config.AddConsole();
            //etc
        );

    

编辑:我为你编写了一个简单的程序来展示它是如何工作的

public class MyClass


    private readonly ILogger<MyClass> _logger;


    public MyClass(ILogger<MyClass> logger)
    
        _logger = logger;
    
    public void MyFunc()
    
        _logger.Log(LogLevel.Error, "My Message");
    




public class Program

    public static void Main(string[] args)
    
        var services = new ServiceCollection().AddLogging(logging => logging.AddConsole());
        services.AddSingleton<MyClass>();//Singleton or transient?!
        var s = services.BuildServiceProvider();
        var myclass = s.GetService<MyClass>();
     

编辑:程序的输出:

【讨论】:

这是一个控制台应用程序,就像问题所说的那样。您在services.AddLogging 中显示的内容与我在问题中的内容有何不同? 让我再问一次。var services = new ServiceCollection()你创建了一个新的服务集合对吗?你在哪里注册到你的应用程序?什么解决了依赖关系?谁创建了 MyClass 的新实例 好吧,伙计,既然你拒绝了帮助 :) 除了建议阅读 DI 之外,我无能为力了 抱歉,它应该是这样工作还是应该不工作 这显示了它应该如何工作,正如您在示例代码中看到的那样,它可以工作并且 logger 是一个 ConsoleLogger。我不明白为什么我们不能互相理解:(【参考方案3】:

在 .NET Core 中,ILogger&lt;T&gt; 会自动为您注册。由于ILogger&lt;T&gt; 继承自ILogger,您可以从IServiceProvider 请求ILogger&lt;T&gt; 的实例。

例如: services.AddSingleton&lt;ILogger&gt;(svc =&gt; svc.GetRequiredService&lt;ILogger&lt;MyClassType&gt;&gt;());

请注意,只要您有一个非泛型 ILogger 构造函数参数,这将返回一个 ILogger&lt;MyClassType&gt;,因此如果您需要多个参数,请考虑使用 AddSingleton 专门为该实例创建它(或瞬态/或作用域) implementationFactory 覆盖。

【讨论】:

【参考方案4】:

正如评论中所述,接受的答案存在BuildServiceProvider 不应在ConfigureServices 中使用的问题,因为它会创建每个单例(实际上是整个 DI 容器)的另一个副本。这是避免该问题的替代单线。在ConfigureServices 中添加一行

services.AddSingleton<Microsoft.Extensions.Logging.ILogger>(provider => 
   provider.GetRequiredService<Microsoft.Extensions.Logging.ILogger<AnyClass>>());

AnyClass 可以是任何类,如接受的答案中所述。这会将ILogger 的分辨率重定向到ILogger&lt;AnyClass&gt; 的分辨率。

与公认的答案一样,这个问题的缺点是 Serilog 的 SourceContext 将被设置为 AnyClass。因此,如果您的 Serilog 配置包含一个包含 SourceContextoutputTemplate,您的日志将显示 AnyClass 而不是包含日志记录语句的类。

【讨论】:

这是一个很好的方法。时尚干净。【参考方案5】:

此答案不一定适用于 .net Core 或海报使用的任何依赖注入。我遇到了这个寻找一种在 asp.net 表单 Web 应用程序中使用 Autofac 修复此错误的方法。日志没有“默认注册”的答案导致我将其添加到我的注册中:

builder.RegisterType<LoggerFactory>().As<ILoggerFactory>().SingleInstance();
builder.RegisterGeneric(typeof(Logger<>)).As(typeof(ILogger<>)).SingleInstance();

现在它对我有用。这是我第二次搜索这个答案并最终来到这里,我忘记了我第一次是如何修复它的。所以我想我会发布我的答案。

【讨论】:

【参考方案6】:

对于 .NET Core 3.1,请务必包含

Microsoft.Extensions.Logging

通过调用打包和配置日志记录

IServiceCollection services = new ServiceCollection();
services.AddLogging();

【讨论】:

这是我一直在寻找的真正答案... 【参考方案7】:

根据@Barry 回答above 了解如何为Microsoft.Extensions.DependencyInjection 注册通用日志提供程序:

var services = new ServiceCollection()
                            .AddLogging(logging => logging.AddConsole())
                            .BuildServiceProvider();

services.AddSingleton<ILoggerFactory, LoggerFactory>()
services.Add(ServiceDescriptor.Describe(typeof(ILogger<>),typeof(Logger<>),ServiceLifetime.Scoped))

【讨论】:

【参考方案8】:

我在尝试使用 ILogger 时使用的方法(因为它不再被注入),例如注入 ILoggerFactory,然后当您的代码需要特定的记录器时(比如说它的某个自定义工厂,您是 @ 987654323@ing up, LoggerFactory.CreateLogger("Logger Name") - 下面

但对于你的情况,看起来你想要一个ILogger&lt;MyClass&gt;

public class MyClass


    private readonly ILoggerFactory _loggerFactory;


    public MyClass(ILoggerFactory loggerFactory)
    
        _loggerFactory = _loggerFactory;
    
    public void MyFunc()
    
       new MyNewThatsASpecialCase(_loggerFactory.CreateLogger("MyNewThatsASpecialCase"));
    

【讨论】:

这对我有用,因为 LoggerFactory 是我请求服务时唯一可用的实例,而不是类记录器。【参考方案9】:

这就是我让 DI 为 ILogger 工作的原因。

对于 .NET Core,请参阅: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-5.0

具体来说:

.ConfigureLogging(logging =>
            
                logging.ClearProviders();
                logging.AddConsole();
            )

参考:

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
    .ConfigureLogging(logging =>
    
        logging.ClearProviders();
        logging.AddConsole();
    )
    .ConfigureWebHostDefaults(webBuilder =>
    
        webBuilder.UseStartup<Startup>();
    );

【讨论】:

净 6.0 docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/…【参考方案10】:

对于使用 NLog 遇到此错误的任何人,我发现我在依赖注入中犯了以下错误:

        private readonly ILogger _logger;

        public ErrorController(ILogger ilogger)
        
            _logger = ilogger;
        

According to the documentation,在 .Net 5 中,您需要将 Controller 本身的类型添加到记录器以避免此问题。这样的依赖注入修复了错误:

        private readonly ILogger<ErrorController> _logger;

        public ErrorController(ILogger<ErrorController> ilogger)
        
            _logger = ilogger;
        

进行上述更改后,这解决了我的问题。不要在这里尝试任何解决方案!这只会让你陷入困境。

希望这对将来的任何人都有帮助!

【讨论】:

【参考方案11】:

接受的答案(由@sam-shiles 提供)朝着正确的方向发展。我不喜欢它需要构建一个中间服务提供者,并且可能也不需要注册单例实例。

所以,我建议注册一个工厂,而不是使用ILoggerFactory。创建一个空类(如AnyClass 也不需要)。

...
services.AddTransient(provider =>

    var loggerFactory = provider.GetRequiredService<ILoggerFactory>();
    const string categoryName = "Any";
    return loggerFactory.CreateLogger(categoryName);
);
...

【讨论】:

以上是关于无法从 Microsoft.Extensions.Logging 解析 ILogger的主要内容,如果未能解决你的问题,请参考以下文章

命名空间Microsoft.Extensions中不存在缓存

无法使用 COM 加载文件或程序集“Microsoft.Extensions.DependencyInjection.Abstractions”

无法加载文件或程序集 Microsoft.Extensions.DependencyInjection.Abstractions,版本 = 1.1.0.0

无法解析类型“Microsoft.Extensions.Logging.ILogger`1[WebApplication1.Startup]”的服务

无法在 Azure Functions 中加载文件或程序集“Microsoft.Extensions.Configuration.Abstractions,版本=5.0.0.0

Azure 函数 5 和 EF Core 5 无法加载文件或程序集 > Microsoft.Extensions.DependencyInjection.Abstractions