在后台作业中使用记录器时出现异常 (ASP.NET Core / Serilog)
Exception while using logger in background job (ASP.NET Core / Serilog)
我在使用 ASP.NET 核心 WebApi 的即发即弃后台作业的上下文中使用记录器时遇到问题。
使用 logger.LogInformation("some message") 时。发生以下异常:
Newtonsoft.Json.JsonSerializationException: Could not create an instance of type Microsoft.Extensions.Logging.ILogger. Type is an interface or abstract class and cannot be instantiated. Path '', line 1, position 2.
很明显,hangfire 似乎无法根据应用程序 bootstrap.
中指示的参数解析记录器的实例化
我确定:
- Hangfire 已正确配置并正常工作
- 记录器(使用 Serilog)在与应用程序相同的范围内使用时(不在后台)工作
- 服务注入适用于 ILogger 以外的其他服务的后台作业
这是我的配置:
Program.cs
public static IWebHost BuildWebHost (string[] args) =>
WebHost.CreateDefaultBuilder (args)
.UseStartup<Startup> ()
.UseSerilog ()
.Build ();
Startup.cs
public Startup (IHostingEnvironment env) {
Log.Logger = new LoggerConfiguration ()
.MinimumLevel.Debug ()
.MinimumLevel.Override ("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext ()
.WriteTo.Console ()
.WriteTo.Debug ()
.WriteTo.RollingFile (System.IO.Path.Combine ("logs/{Date}-logs.txt"))
.CreateLogger ();
}
public void ConfigureServices (IServiceCollection services) {
services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(dispose: true));
// ... registering other services
services.AddMvc ();
services.AddHangfire (conf => conf.UseSqlServerStorage (Configuration.GetConnectionString ("HangFire")));
}
public void Configure (IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider) {
app.UseMvc ();
//hangfire
GlobalConfiguration.Configuration.UseActivator(new HangfireActivator(serviceProvider));
app.UseHangfireServer ();
app.UseHangfireDashboard ();
}
HangfireActivator
public class HangfireActivator : Hangfire.JobActivator {
private readonly IServiceProvider _serviceProvider;
public HangfireActivator (IServiceProvider serviceProvider) {
_serviceProvider = serviceProvider;
}
public override object ActivateJob (Type type) {
Debug.WriteLine("ActivateJob() => " + type.Name);
return _serviceProvider.GetService (type);
}
}
ValueController.cs
public class ValuesController : Controller {
private readonly ILogger<ValuesController> logger;
private readonly SomeService someService;
public ValuesController (ILogger<ValuesController> logger, SomeService someService) {
this.logger = logger;
this.someService = someService;
}
[Route ("task")]
public JsonResult StartTask () {
var server = new BackgroundJobServer ();
BackgroundJob.Enqueue(() => logger.LogInformation("HELLO from background job instanciated logger"));
return new JsonResult (new { Result = "task started" });
}
}
我错过了什么吗?
对相关主题的任何帮助或 link 将不胜感激。感谢您的帮助!
我讨厌收到那种答案,但在这种情况下,通用 "do not use it" 比浪费时间寻找具体解决方案要好。至少不要将记录器提供程序用于后台作业(它可以为您提供什么优势?)。如果您不想看到 SerialLog 引用 - 将其包装到您自己的接口和实现中。 LoggerProvider 是一个巨大的抽象泄漏 (https://github.com/aspnet/EntityFrameworkCore/issues/10420),因为它不是您所期望的真正的 DI,而是具有奇特行为的服务定位器。
甚至更多:DI 根本无法提供良好的日志记录。良好的日志记录不仅是跟踪,而且是灵活的审计,并且始终 每个会话 例如假设您只想启用来自特定测试用户的详细日志记录,并将他的每个会话记录到特定文件(很自然的要求,试图重复用户问题并快速分析情况)。您无法使用希望在每个使用它的地方从 IoC 容器获取的记录器来实现这一点,相反,您应该在会话开始时构建它并仔细传递所有构造函数(有时是远程服务)"manually".
不要依赖DI。功能齐全。更像 node.js 而不是 MVC。就像 "less razor" 比 "more razor" 好(使用应该有动力)。
正如我所说,我也讨厌收到这样的答案。
侧不是...在 Main() 或 Startup classes 中使用静态日志配置 Serilog 记录器 class 使我能够使用 serilog 解决此错误...这有效对我来说:
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext()
.WriteTo.ColoredConsole()
.CreateLogger();
然后在 Hangfire 的 Enqueue() 方法中调用 Log.Information($"");
我在使用 ASP.NET 核心 WebApi 的即发即弃后台作业的上下文中使用记录器时遇到问题。 使用 logger.LogInformation("some message") 时。发生以下异常:
Newtonsoft.Json.JsonSerializationException: Could not create an instance of type Microsoft.Extensions.Logging.ILogger. Type is an interface or abstract class and cannot be instantiated. Path '', line 1, position 2.
很明显,hangfire 似乎无法根据应用程序 bootstrap.
中指示的参数解析记录器的实例化我确定:
- Hangfire 已正确配置并正常工作
- 记录器(使用 Serilog)在与应用程序相同的范围内使用时(不在后台)工作
- 服务注入适用于 ILogger 以外的其他服务的后台作业
这是我的配置:
Program.cs
public static IWebHost BuildWebHost (string[] args) =>
WebHost.CreateDefaultBuilder (args)
.UseStartup<Startup> ()
.UseSerilog ()
.Build ();
Startup.cs
public Startup (IHostingEnvironment env) {
Log.Logger = new LoggerConfiguration ()
.MinimumLevel.Debug ()
.MinimumLevel.Override ("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext ()
.WriteTo.Console ()
.WriteTo.Debug ()
.WriteTo.RollingFile (System.IO.Path.Combine ("logs/{Date}-logs.txt"))
.CreateLogger ();
}
public void ConfigureServices (IServiceCollection services) {
services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(dispose: true));
// ... registering other services
services.AddMvc ();
services.AddHangfire (conf => conf.UseSqlServerStorage (Configuration.GetConnectionString ("HangFire")));
}
public void Configure (IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider) {
app.UseMvc ();
//hangfire
GlobalConfiguration.Configuration.UseActivator(new HangfireActivator(serviceProvider));
app.UseHangfireServer ();
app.UseHangfireDashboard ();
}
HangfireActivator
public class HangfireActivator : Hangfire.JobActivator {
private readonly IServiceProvider _serviceProvider;
public HangfireActivator (IServiceProvider serviceProvider) {
_serviceProvider = serviceProvider;
}
public override object ActivateJob (Type type) {
Debug.WriteLine("ActivateJob() => " + type.Name);
return _serviceProvider.GetService (type);
}
}
ValueController.cs
public class ValuesController : Controller {
private readonly ILogger<ValuesController> logger;
private readonly SomeService someService;
public ValuesController (ILogger<ValuesController> logger, SomeService someService) {
this.logger = logger;
this.someService = someService;
}
[Route ("task")]
public JsonResult StartTask () {
var server = new BackgroundJobServer ();
BackgroundJob.Enqueue(() => logger.LogInformation("HELLO from background job instanciated logger"));
return new JsonResult (new { Result = "task started" });
}
}
我错过了什么吗? 对相关主题的任何帮助或 link 将不胜感激。感谢您的帮助!
我讨厌收到那种答案,但在这种情况下,通用 "do not use it" 比浪费时间寻找具体解决方案要好。至少不要将记录器提供程序用于后台作业(它可以为您提供什么优势?)。如果您不想看到 SerialLog 引用 - 将其包装到您自己的接口和实现中。 LoggerProvider 是一个巨大的抽象泄漏 (https://github.com/aspnet/EntityFrameworkCore/issues/10420),因为它不是您所期望的真正的 DI,而是具有奇特行为的服务定位器。
甚至更多:DI 根本无法提供良好的日志记录。良好的日志记录不仅是跟踪,而且是灵活的审计,并且始终 每个会话 例如假设您只想启用来自特定测试用户的详细日志记录,并将他的每个会话记录到特定文件(很自然的要求,试图重复用户问题并快速分析情况)。您无法使用希望在每个使用它的地方从 IoC 容器获取的记录器来实现这一点,相反,您应该在会话开始时构建它并仔细传递所有构造函数(有时是远程服务)"manually".
不要依赖DI。功能齐全。更像 node.js 而不是 MVC。就像 "less razor" 比 "more razor" 好(使用应该有动力)。
正如我所说,我也讨厌收到这样的答案。
侧不是...在 Main() 或 Startup classes 中使用静态日志配置 Serilog 记录器 class 使我能够使用 serilog 解决此错误...这有效对我来说:
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext()
.WriteTo.ColoredConsole()
.CreateLogger();
然后在 Hangfire 的 Enqueue() 方法中调用 Log.Information($"");