Asp.net Core Quartz 作业调用控制器方法,但上下文

问题描述

我有一个 aspnetcore 服务器(为 Blazor wasm 应用程序提供服务),它有一个 Quartz 计划作业正在运行。当作业触发时,它会调用我的一个服务器控制器上的方法

如果我在我的控制器上正常调用这个方法(例如通过 Web API 调用),它工作正常。

当我从 Quartz IJob 调用方法时,控制器中使用的 DbContext 似乎已被释放。 我已经尝试以正常方式以及通过 IServiceProvider 将控制器注入到作业中,两者都具有相同的结果。

控制器:

public class NotificationController : ControllerBase
{
    private readonly ApplicationDbContext context;
    
    public NotificationService(ApplicationDbContext context)
    {
        this.context = context;
    }

    public async Task MyMethod()
    {
        await context.SaveChangesAsync(); //This is where it fails when Quartz calls it,seems context is not populated
    }
}

我的工作(IServiceProvider 尝试):

public class ReminderJob : IJob
{
    private readonly IServiceProvider serviceProvider;

    public ReminderJob(IServiceProvider serviceProvider)
    {
        this.serviceProvider = serviceProvider;
    }

    public async Task Execute(IJobExecutionContext jobcontext)
    {
        using (var scope = serviceProvider.CreateScope())
        {
            await scope.ServiceProvider.GetrequiredService<NotificationController>().MyMethod();
        }
    }
}

我的工作(DI 尝试):

public class ReminderJob : IJob
{
    private readonly NotificationController notificationController;

    public ReminderJob(NotificationController notificationController)
    {
        this.notificationController = notificationController;
    }

    public async Task Execute(IJobExecutionContext jobcontext)
    {
        await notificationController.MyMethod();
    }
}

我的 Startup.cs(ConfigureServices 中的相关行):

public void ConfigureServices(IServiceCollection services)
    {
        services.AddSignalR();
        services.AddControllersWithViews();
        services.AddMvcCore().AddControllersAsServices();
        services.AddRazorPages();

        services.AddQuartz(q =>
        {
            q.UseMicrosoftDependencyInjectionScopedJobFactory(); //I also tried passing options.CreateScope to this method,but no difference
            q.AddJobAndTrigger<ReminderJob>(configuration);
        });
        services.AddQuartzHostedService(q => q.WaitForJobsToComplete = true);

        services.AddDbContext<ApplicationDbContext>(options => 
               options.UsesqlServer(configuration.GetConnectionString("DefaultConnection")));

}

VS 尝试执行 context.SaveChangesAsync() 时没有抛出异常,但是,在它没有命中后直接断点,但是当我在调试时检查上下文的详细信息时,它似乎没有被填充正确。

如何在 IJob 中使用 Controller,并确保 Controller 的依赖项不会被处理?

解决方法

如何在 IJob 中使用控制器

请勿在 Job 中使用控制器。

将所需的功能移动/提取/重构为服务抽象

//Service abstraction
public interface INotificationService {
    Task MyMethod();
}

public class NotificationService : INotificationService {
    private readonly ApplicationDbContext context;

    public NotificationService(ApplicationDbContext context) {
        this.context = context;
    }

    public async Task MyMethod() {
        await context.SaveChangesAsync();
    }
}

让作业和控制器依赖于服务来调用所需的功能。

public class NotificationController : ControllerBase {
    private readonly INotificationService service;
    
    public NotificationController (INotificationService service ) {
        this.service = service ;
    }    

    public async Task<IActionResult> MyMethod() {
        await service.MyMethod(); 
        return Ok();
    }
}

public class ReminderJob : IJob {
    private readonly INotificationService service;

    public ReminderJob(INotificationService service) {
        this.service = service;
    }

    public Task Execute(IJobExecutionContext jobcontext) {
        return service.MyMethod();
    }
}

当然还要向 DI 容器注册所有必要的服务。

//...

services.AddScoped<INotificationService,NotificationService>();

//...

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...