无法从 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;
}
进行上述更改后,这解决了我的问题。不要尝试这里的任何解决方案!这只会让你陷入困境。
希望这对以后的任何人都有帮助!
我已经像这样配置了控制台应用程序的 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;
}
进行上述更改后,这解决了我的问题。不要尝试这里的任何解决方案!这只会让你陷入困境。
希望这对以后的任何人都有帮助!