无法从Microsoft.Extensions.Logging解析ILogger

时间:2018-10-22 03:16:38

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

我已经这样配置了控制台应用程序的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)时,都必须重复此操作。

8 个答案:

答案 0 :(得分:10)

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现在将通过构造函数注入来解析

答案 1 :(得分:4)

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

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

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

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

答案 2 :(得分: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>();
     }
}

enter image description here 编辑:程序输出: enter image description here

答案 3 :(得分:2)

在.NET Core中,ILogger<T>将自动为您注册。由于ILogger<T>继承自ILogger,因此您可以从ILogger<T>请求IServiceProvider的实例。

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

请注意,只要您有一个非通用的ILogger<MyClassType>构造函数参数,它就会返回一个ILogger,因此,如果您需要多个参数,请考虑使用{ {1}}(或临时/或作用域)的ImplementationFactory覆盖。

答案 4 :(得分:2)

基于@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))

答案 5 :(得分:0)

我尝试使用server { listen 80; server_name test.myserver.com; root /www/; location = / { } location /index.html { } location / { proxy_pass http://192.168.0.170; } } (因为不再注入),注入ILogger,然后在代码需要特定记录器时使用的方法(例如,它是一些自定义工厂您ILoggerFactorynew-在下面

但是对于您而言,您似乎想要LoggerFactory.CreateLogger("Logger Name")

ILogger<MyClass>

答案 6 :(得分:0)

此答案不一定适用于.net Core或发布者正在使用的任何依赖项注入。我在此搜索中寻找了一种在asp.net表单Web应用程序中使用Autofac修复此错误的方法。日志记录未“默认注册”的答案导致我将其添加到我的注册中:

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

现在它对我有用。这是我第二次搜索该答案并结束于此处,却忘记了如何第一次修复它。所以我想我会发布答案。

答案 7 :(得分:0)

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