如何将Quartz Scheduler任务执行状态返回至ASP.NET MVC视图?
在ASP.NET MVC中跟踪Quartz.NET任务执行状态的可行方案
因为ViewBag和Session依赖请求生命周期,无法跨长时间运行的任务传递状态,你可以采用以下几种方案:
1. 持久化存储(支持多服务器场景)
将任务状态存储到数据库、Redis等持久化介质中,视图端通过接口获取状态更新UI。
在任务监听器的JobWasExecuted方法中更新状态:
public async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default) { var jobId = context.JobDetail.Key.Name; var status = jobException == null ? "Completed" : "Failed"; // 示例:用EF更新数据库中的任务状态表 using (var dbContext = new YourDbContext()) { var taskStatus = await dbContext.TaskStatuses .FirstOrDefaultAsync(t => t.JobId == jobId, cancellationToken); if (taskStatus != null) { taskStatus.Status = status; taskStatus.FinishTime = DateTime.UtcNow; await dbContext.SaveChangesAsync(cancellationToken); } } }
在控制器中提供获取状态的接口:
public JsonResult GetJobStatus(string jobId) { using (var dbContext = new YourDbContext()) { var status = dbContext.TaskStatuses .Where(t => t.JobId == jobId) .Select(t => t.Status) .FirstOrDefault() ?? "Unknown"; return Json(new { Status = status }, JsonRequestBehavior.AllowGet); } }
视图端通过AJAX定时轮询该接口,更新页面元素。
2. 内存缓存+静态线程安全容器(单服务器场景)
适合单服务器部署的项目,用线程安全的容器存储状态,避免并发问题。
先定义静态状态跟踪类:
public static class JobStatusTracker { private static readonly ConcurrentDictionary<string, string> _jobStatuses = new ConcurrentDictionary<string, string>(); public static void UpdateJobStatus(string jobId, string status) { _jobStatuses.AddOrUpdate(jobId, status, (key, oldVal) => status); } public static string GetJobStatus(string jobId) { _jobStatuses.TryGetValue(jobId, out var status); return status ?? "Running"; } }
在监听器中更新状态:
public async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default) { var jobId = context.JobDetail.Key.Name; var status = jobException == null ? "Completed" : "Failed"; JobStatusTracker.UpdateJobStatus(jobId, status); await Task.CompletedTask; }
控制器接口获取状态:
public JsonResult GetJobStatus(string jobId) { var status = JobStatusTracker.GetJobStatus(jobId); return Json(new { Status = status }, JsonRequestBehavior.AllowGet); }
3. SignalR实时推送(最佳实时体验)
通过SignalR在任务完成时主动向客户端推送状态,无需轮询,实时性更好。
创建SignalR Hub:
public class JobStatusHub : Hub { public async Task SendJobStatusUpdate(string jobId, string status) { await Clients.All.SendAsync("ReceiveJobStatus", jobId, status); } }
在监听器中注入HubContext并推送状态:
private readonly IHubContext<JobStatusHub> _hubContext; public YourJobListener(IHubContext<JobStatusHub> hubContext) { _hubContext = hubContext; } public async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default) { var jobId = context.JobDetail.Key.Name; var status = jobException == null ? "Completed" : "Failed"; await _hubContext.Clients.All.SendAsync("ReceiveJobStatus", jobId, status, cancellationToken); }
视图端监听推送并更新UI:
<script src="~/lib/signalr/signalr.min.js"></script> <script> const connection = new signalR.HubConnectionBuilder() .withUrl("/jobStatusHub") .build(); connection.on("ReceiveJobStatus", (jobId, status) => { // 根据任务ID匹配并更新页面状态 if (jobId === "@Model.JobId") { document.getElementById("jobStatusDisplay").textContent = `任务状态:${status}`; } }); connection.start().catch(err => console.error(err.toString())); </script>
内容的提问来源于stack exchange,提问作者MrMustafa022
相关产品推荐
相关产品推荐

