无法解析 Microsoft.Extensions.Logging 中的 ILogger

我已经像这样设置了我的控制台应用的 abc 0

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: ‘无法解析类型的服务 微软,扩展,日志,ILogger

我已经尝试了解决方案 给你,但它不适合我。

剪辑 根据雅科夫下面的评论和 这个 Github 评论,我能够正确地解决这个问题

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

我希望在初始的 BuildServiceProvider中使用这个命令,但是看起来每次我想使用日志记录器(或者创建我自己的 ILogger)时都必须重复这个命令。

127335 次浏览

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

默认情况下,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 核心,ILogger<T>会自动为您注册。由于 ILogger<T>继承自 ILogger,因此可以从 IServiceProvider请求 ILogger<T>的实例。

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

请注意,只要您有非通用的 ILogger构造函数参数,它就会返回一个 ILogger<MyClassType>,因此如果您需要不止一个 ILogger构造函数参数,那么可以通过使用 AddSingleton(或暂时/或作用域的)实现 Factory 覆盖来专门为该实例创建它。

我在尝试使用 ILogger(因为它不再被注入)时使用的方法,例如注入一个 ILoggerFactory,然后当你的代码需要一个特定的日志记录器(比如它的一些自定义工厂,你是 newing 上,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"));
}
}

这个答案不一定是为了。网络核心或者其他什么依赖注入被海报使用。我在 asp.net 表单 web 应用程序中使用 Autofac 来寻找修复这个错误的方法。没有“默认注册”日志的答案让我把这个加到我的注册中:

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

现在对我有用了。这是我第二次搜索这个答案,结果在这里,我忘记了我是如何修正它的第一次。所以我想我应该把我的答案贴出来。

正如注释中指出的,接受的答案有一个问题,即 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。因此,如果 Serillog 配置包含一个包含 {SourceContext}outputTemplate,那么您的日志将显示 AnyClass,而不是包含日志语句的类。

基于@巴里答案 以上找到了如何为 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 核心,请参阅: Https://learn.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。创建一个空类(也不需要像 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;
}

根据文件 ,在。Net5中,您需要将 Controller 本身的类型添加到日志记录器中,以避免这个问题。依赖注入修复了错误:

        private readonly ILogger<ErrorController> _logger;


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

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

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