在后台作业中使用记录器时出现异常(ASP.NET Core / Serilog)

时间:2017-12-26 15:23:58

标签: logging dependency-injection asp.net-core hangfire

在使用ASP.NET Core WebApi进行即发即弃后台作业的上下文中使用记录器时遇到问题。 使用logger.LogInformation(“some message”)时。发生以下异常:

  

Newtonsoft.Json.JsonSerializationException:无法创建Microsoft.Extensions.Logging.ILogger类型的实例。 Type是接口或抽象类,无法实例化。路径'',第1行,第2位。

很明显,似乎hangfire无法根据应用程序引导程序中指示的参数来解决记录器的实例。

我确信:

  • 正确配置Hangfire并正常工作
  • 记录器(使用Serilog)在与app相同的范围内使用(不在backgorund中)
  • 服务注入适用于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" });
        }
}

我错过了什么吗? 任何帮助或相关主题的链接将不胜感激。谢谢你的帮助!

2 个答案:

答案 0 :(得分:1)

我讨厌接受这样的答案,但是这种情况下通用的“不使用它”比浪费时间找到特定的解决方案更好。只是不要使用记录器提供程序至少用于后台作业(它可以为您提供哪些优势?)。如果您不想查看SerialLog引用 - 将其包装到您自己的接口和实现中。 LoggerProvider是一个巨大的抽象泄漏(https://github.com/aspnet/EntityFrameworkCore/issues/10420),因为它不是一个真正的DI,你可以期待但服务定位器具有奇特的行为。

甚至更多:DI根本无法提供良好的日志记录。良好的日志记录不仅仅是跟踪而是灵活的审计,并且总是每个会话,例如想象一下,您只想从特定测试用户启用详细日志记录,并将每个会话记录到特定文件(非常自然的要求,尝试重复用户问题并快速分析情况)。您无法通过您希望从IoC容器中使用它的每个位置获得的记录器实现此目的,相反,您应该在会话开始时构建它并“仔细”通过所有构造函数(有时是远程服务)“手动”。

不要依赖DI。功能齐全。更像node.js而不是MVC。这就像“少剃刀”比“更多剃刀”更好(使用应该是动机)。

正如我所说,我也讨厌得到这样的答案。

答案 1 :(得分:0)

侧面不是...使用静态Log类在Main()或Startup类中配置Serilog记录器,这使我能够解决serilog的错误...这对我有用:

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Debug()
    .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
    .Enrich.FromLogContext()
    .WriteTo.ColoredConsole()
    .CreateLogger();

然后在Hangfire的Enqueue()方法中只需调用Log.Information($“”);