C# 在Asp.NET内核中触发Quartz作业时释放上下文
我正在尝试从.NETCore中的WebAPI控制器构建一个触发石英作业。 我已经成功地从启动类创建了一个具有简单计划的触发器:C# 在Asp.NET内核中触发Quartz作业时释放上下文,c#,asp.net-core,C#,Asp.net Core,我正在尝试从.NETCore中的WebAPI控制器构建一个触发石英作业。 我已经成功地从启动类创建了一个具有简单计划的触发器: public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider services) { loggerFactory.AddConsole(this.Conf
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider services)
{
loggerFactory.AddConsole(this.Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseCors("CorsPolicy");
app.UseApplicationInsightsRequestTelemetry();
app.UseApplicationInsightsExceptionTelemetry();
app.UseMvc();
ProcessTracksScheduler.Start(services);
}
以下是启动方法:
public static class ProcessTracksScheduler
{
public static void Start(IServiceProvider provider)
{
try
{
ISchedulerFactory schedFact = new StdSchedulerFactory();
IScheduler sched = schedFact.GetScheduler();
sched.Start();
IJobDetail job = JobBuilder.Create<ProcessTracksJob>()
.WithIdentity("ProcessTracks", "Group1")
.Build();
job.JobDataMap["tracksService"] = provider.GetService(typeof(ITracksService));
job.JobDataMap["cloudService"] = provider.GetService(typeof(ICloudService));
job.JobDataMap["broadcastService"] = provider.GetService(typeof(IBroadcastService));
job.JobDataMap["categoriesService"] = provider.GetService(typeof(ICategoriesService));
ITrigger trigger = TriggerBuilder.Create()
.WithSimpleSchedule(x => x
.RepeatForever()
.WithInterval(TimeSpan.FromDays(1)))
.StartNow()
.Build();
sched.ScheduleJob(job, trigger);
}
catch (ArgumentException e)
{
// Log the error
}
}
}
因此,这一个工程如预期,我很高兴与它!但这里的问题是,当我试图构建一个触发器,使作业仅从我的web API控制器启动一次时:
[Route("Proccess")]
[HttpPost]
public async Task<IActionResult> ProccessTracks()
{
ProcessTracksScheduler.StartOnce(serviceProvider);
return Ok("Job scheduled");
}
我尝试了很多方法,但找不到解决此问题的任何方法。您是否尝试过在构造函数的
ProcessTracksJob
类中要求服务?我像这样使用它,没有任何问题
使用JobDataMap插入
public class ProcessTracksJob :IJob
{
private readonly ITracksService _tracksService;
public ProcessTracksJob(ITracksService tracksService, etc.)
{
_tracksService = tracksService;
...
}
/// the execute method using the private fields in this class
}
您的Quartz代码是否在ASP.NET应用程序中运行?如果是这样,你就不应该那样做。ASP.NET用于短时间运行的任务,然后结束。通过在其中扩展它(如运行Quartz),您违反了ASP.NET的原则。它将在其生命周期结束时终止。相反,应用程序应该与包含石英代码的专用进程通信。我的石英代码位于另一个项目中,而不是ASP.NET应用程序中。这就是你的意思吗?那个项目正在创建一个可执行文件吗?不,你说得对。quartz作业在ASP.NET应用程序中执行。但现在这并不是一个真正的问题,这项工作一点也不繁重。不管它有多繁重,你都无法控制ASP.NET和IIS何时会回收应用程序池,或者任何数量的可能性。任何超过几秒钟的运行都有可能被终止。因此,正如您所想象的那样,试图在将来安排一整天的时间来运行某些东西是行不通的。如果您的类是从IJob
派生的,那么它将毫无问题地执行该方法。此外,请记住在DI库中注册它,以便能够将这些服务注入构造函数中。我使用这种方法没有问题。是否有任何错误?完全没有错误,请在execute方法中放置一个断点,但它不会命中它。。在我的DI库中注册它,您的意思是这样的:services.AddTransient()代码>在ConfigureService(IServiceCollection服务)
方法中?对于DI,我使用的作业类如下:builder.RegisterType().AsSelf()代码>(自动传真)。石英配置对我来说是一样的。对于测试,我使用较小的触发器时间跨度。我不希望使用Autofac,因为Asp.NET-core已经处理DI…可能是生命周期已过期,您是否尝试过不同的生命周期服务?(范围限定,单例)
public static void StartOnce(IServiceProvider provider)
{
try
{
ISchedulerFactory schedFact = new StdSchedulerFactory();
IScheduler sched = schedFact.GetScheduler();
sched.Start();
IJobDetail job = JobBuilder.Create<ProcessTracksJob>()
.WithIdentity("ProcessTracksOnce", "Group1")
.Build();
job.JobDataMap["tracksService"] = provider.GetService(typeof(ITracksService));
job.JobDataMap["cloudService"] = provider.GetService(typeof(ICloudService));
job.JobDataMap["broadcastService"] = provider.GetService(typeof(IBroadcastService));
job.JobDataMap["categoriesService"] = provider.GetService(typeof(ICategoriesService));
ITrigger trigger = TriggerBuilder.Create()
.StartNow()
.Build();
sched.ScheduleJob(job, trigger);
}
catch (ArgumentException e)
{
// Log the error
}
}
// In Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(this.Configuration.GetConnectionString("MyConnString")));
services.AddTransient<IBroadcastService, BroadcastsService>();
// Add the others services.
}
public class ProcessTracksJob :IJob
{
private readonly ITracksService _tracksService;
public ProcessTracksJob(ITracksService tracksService, etc.)
{
_tracksService = tracksService;
...
}
/// the execute method using the private fields in this class
}