无法从 Microsoft.Extensions.Logging 解析 ILogger

Unable to resolve ILogger from Microsoft.Extensions.Logging

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

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

然后我尝试在另一个 class 中使用它,就像这样

private readonly ILogger _logger;
    
public MyClass(ILogger logger)
{
    _logger = logger;
}

public void MyFunc()
{
    _logger.Log(LogLevel.Error, "My Message");
}

System.InvalidOperationException: 'Unable to resolve service for type 'Microsoft.Extensions.Logging.ILogger'

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

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

public MyClass(ILogger<MyClass> logger)
{
    _logger = logger;
}

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

我假设您使用的是 .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>();
     }
}

编辑:程序输出:

ILogger 默认不再注册,但 ILogger<T> 注册。如果您仍然想使用 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 现在将通过构造函数注入解析。

在 .NET Core 中,ILogger<T> 会自动为您注册。由于 ILogger<T> 继承自 ILogger,您可以从 IServiceProvider.

请求 ILogger<T> 的实例

例如: services.AddSingleton<ILogger>(svc => svc.GetRequiredService<ILogger<MyClassType>>());

请注意,只要你有一个非泛型 ILogger 构造函数参数,这将 return 一个 ILogger<MyClassType>,所以如果你需要多个构造函数参数,请考虑专门为该实例通过使用 AddSingleton(或 transient/or 作用域)implementationFactory 覆盖。

我在尝试使用 ILogger 时使用的方法(因为它不再注入),注入 ILoggerFactory,然后当您的代码需要特定的记录器时(比如它的一些您正在 new 定制工厂,LoggerFactory.CreateLogger("Logger Name") - 低于

但是对于你的情况,你似乎想要一个 ILogger<MyClass>

public class MyClass
{

    private readonly ILoggerFactory _loggerFactory;


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

这个答案不一定适用于 .net Core 或 poster 使用的任何依赖注入。我 运行 通过搜索在 asp.net 表单 Web 应用程序中使用 Autofac 来修复此错误的方法。日志记录未被“默认注册”的答案导致我将其添加到我的注册中:

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

现在对我有用了。这是我第二次搜索这个答案并在这里结束,我忘记了第一次是如何修复它的。所以我想我会 post 我的答案。

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

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

其中 AnyClass 可以是任何 class,如接受的答案中所述。这会将 ILogger 的分辨率重定向到 ILogger<AnyClass>.

的分辨率

与已接受的答案一样,该答案的缺点是 Serilog 的 SourceContext 将设置为 AnyClass。因此,如果您的 Serilog 配置包含包含 {SourceContext}outputTemplate,您的日志将显示 AnyClass 而不是包含日志语句的 class。

基于@Barry answer 了解如何为 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))

这就是让 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>();
    });

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

Microsoft.Extensions.Logging

调用

打包配置日志
IServiceCollection services = new ServiceCollection();
services.AddLogging();

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

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

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

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

        private readonly ILogger _logger;

        public ErrorController(ILogger ilogger)
        {
            _logger = ilogger;
        }

According to the documentation,在.Net 5中,为了避免这个问题,你需要给logger添加一个Controller本身的类型。这样的依赖注入修复了错误:

        private readonly ILogger<ErrorController> _logger;

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

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

希望这对以后的任何人都有帮助!