首页 文章

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

提问于
浏览
1

我在使用ASP.NET Core WebApi进行即发即弃后台作业的上下文中使用 Logger 时遇到问题 . 使用logger.LogInformation时(“某些消息”) . 发生以下异常:

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

显然,似乎hangfire无法根据应用程序引导程序中指示的参数来解决 Logger 的实例 .

我确信:

  • Hangfire已正确配置并正常运行

  • Logger (使用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 回答

  • 1

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

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

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

    正如我所说,我也讨厌收到这样的答案 .

  • 0

    方面没有......使用静态Log类在Main()或Startup类中配置Serilog Logger 使我能够使用serilog解决此错误...这对我有用:

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

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

相关问题