118

我已经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'的服务

我已经尝试过这里的解决方案,但它对我不起作用。

编辑 基于下面 Yaakov 的评论和这个 Github 评论,我可以通过这样做正确解决它

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

我本来希望一开始就这样做,BuildServiceProvider但看起来每次我想使用记录器(或创建我自己的 ILogger)时我都必须重复这个。

4

11 回答 11

122

ILogger默认情况下不再注册,但ILogger<T>已注册。如果您仍想使用 ILogger,您可以使用以下代码手动注册它(in 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现在将通过构造函数注入解决。

于 2019-08-21T10:56:27.213 回答
25

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

// 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>();
     }
}

在此处输入图像描述 编辑:程序的输出: 在此处输入图像描述

于 2018-10-22T03:25:54.213 回答
12

在 .NET Core 中,ILogger<T>会自动为您注册。作为ILogger<T>继承自,您可以从ILogger请求一个实例。ILogger<T>IServiceProvider

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

请注意,这将ILogger<MyClassType>在您拥有非泛型ILogger构造函数参数的任何地方返回一个,因此如果您需要多个参数,请考虑使用AddSingleton(或瞬态/或作用域)implementationFactory 覆盖专门为该实例创建它。

于 2020-07-16T08:20:27.850 回答
9

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

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

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

像公认的答案一样,这个具有 SerilogSourceContext将被设置为的缺点AnyClass。因此,如果您的 Serilog 配置包含outputTemplate包含{SourceContext},您的日志将显示AnyClass而不是包含日志记录语句的类。

于 2021-01-12T14:33:43.007 回答
5

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

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

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

于 2020-11-08T23:19:00.473 回答
5

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

Microsoft.Extensions.Logging

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

IServiceCollection services = new ServiceCollection();
services.AddLogging();
于 2021-09-29T21:39:41.373 回答
3

根据上面的@Barry回答,了解如何注册通用日志提供程序: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))
于 2021-01-27T20:51:00.400 回答
2

我在尝试使用时使用的方法ILogger(因为它不再被注入),例如注入 a ILoggerFactory,然后当你的代码需要一个特定的记录器时(比如你正在使用的一些自定义工厂newLoggerFactory.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"));
    }
}
于 2020-07-23T14:43:49.963 回答
1

这就是让 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>();
    });
于 2021-07-23T20:04:32.523 回答
0

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

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

...
services.AddTransient(provider =>
{
    var loggerFactory = provider.GetRequiredService<ILoggerFactory>();
    const string categoryName = "Any";
    return loggerFactory.CreateLogger(categoryName);
});
...
于 2022-01-06T16:44:52.580 回答
0

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

        private readonly ILogger _logger;

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

根据文档,在 .Net 5 中,您需要将控制器本身的类型添加到记录器以避免此问题。这样的依赖注入修复了错误:

        private readonly ILogger<ErrorController> _logger;

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

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

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

于 2022-03-03T19:31:46.890 回答