You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MVC5中如何在Hangfire后台任务完成后发送通知?

在MVC5 + Hangfire中实现后台任务完成后的前端通知

这个场景太常见了——后台任务已经丢给Hangfire跑了,控制器早早就返回了JSON,没法再通过原请求给前端发完成通知对吧?别担心,这里有几个靠谱的解决方案,你可以根据自己的场景选:

方案一:用SignalR实现实时推送(最优雅的方式)

SignalR是ASP.NET的实时通信库,能让服务器主动给前端发消息,完美适配这种后台任务完成通知的场景。

步骤1:配置SignalR

  1. 先通过NuGet安装Microsoft.AspNet.SignalR包
  2. 在Startup.cs里注册SignalR中间件:
using Microsoft.Owin;
using Owin;
using Microsoft.AspNet.SignalR;

[assembly: OwinStartup(typeof(YourProject.Startup))]
namespace YourProject
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // 注册SignalR路由
            app.MapSignalR();
            // 其他现有配置...
        }
    }
}

步骤2:创建通知Hub

新建一个Hub类,用来处理服务器到前端的消息推送:

using Microsoft.AspNet.SignalR;

public class NotificationHub : Hub
{
    // 给指定用户发送完成通知的方法
    public void SendTaskCompleteNotification(string userId, string message)
    {
        // 如果是登录用户,可以用UserId定向推送;如果是匿名用户,也可以用ConnectionId
        Clients.User(userId).receiveTaskComplete(message);
    }
}

步骤3:修改后台任务和控制器

更新你的后台任务,在任务完成后调用SignalR发送通知;同时控制器可以返回任务ID(可选,方便前端关联):

public ActionResult RunMedia(int ID)
{
    // 获取当前登录用户的ID(如果是匿名场景,可以用SessionId或者前端传的标识)
    var userId = User.Identity.GetUserId();
    var jobId = BackgroundJob.Enqueue<CrawlerSearchRequestModel>(x => x.StoreMedia(ID, "NaturalPerson", userId));
    
    return Json(new { success = true, jobId = jobId }, JsonRequestBehavior.AllowGet);
}

// 修改你的CrawlerSearchRequestModel的StoreMedia方法
public void StoreMedia(int ID, string type, string userId)
{
    // 原有的任务逻辑...
    // 任务完成后,调用SignalR发送通知
    var hubContext = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();
    hubContext.Clients.User(userId).receiveTaskComplete($"媒体存储任务ID {ID} 已完成!");
}

步骤4:前端JavaScript连接SignalR

在页面里引入SignalR的脚本,连接Hub并监听通知:

<script src="/Scripts/jquery.signalR-2.4.3.min.js"></script>
<script src="/signalr/hubs"></script>

<script>
    $(function () {
        // 连接SignalR Hub
        var notificationHub = $.connection.notificationHub;
        
        // 定义接收通知的方法
        notificationHub.client.receiveTaskComplete = function (message) {
            // 这里可以用弹窗、Toast等方式展示通知
            alert(message);
            // 或者更新页面元素:$('#notification').text(message);
        };
        
        // 启动连接
        $.connection.hub.start().done(function () {
            console.log("已连接到通知Hub");
        });
    });
</script>

方案二:前端轮询检查任务状态(适合简单场景)

如果不想引入SignalR,也可以用前端定时查询的方式,虽然实时性稍差,但实现简单。

步骤1:控制器返回JobId

修改控制器,把Hangfire任务的JobId返回给前端:

public ActionResult RunMedia(int ID)
{
    var jobId = BackgroundJob.Enqueue<CrawlerSearchRequestModel>(x => x.StoreMedia(ID, "NaturalPerson"));
    return Json(new { success = true, jobId = jobId }, JsonRequestBehavior.AllowGet);
}

步骤2:新增API接口查询任务状态

添加一个控制器方法,用来查询指定JobId的任务状态:

public ActionResult CheckJobStatus(string jobId)
{
    var jobDetails = JobStorage.Current.GetConnection().GetJobData(jobId);
    bool isCompleted = jobDetails.State == "Succeeded";
    return Json(new { isCompleted = isCompleted }, JsonRequestBehavior.AllowGet);
}

步骤3:前端轮询逻辑

在Ajax调用RunMedia成功后,开始定时查询任务状态:

$.ajax({
    url: '/YourController/RunMedia',
    type: 'POST',
    data: { ID: 123 },
    success: function (response) {
        if (response.success) {
            // 每5秒查询一次任务状态
            var pollInterval = setInterval(function () {
                $.ajax({
                    url: '/YourController/CheckJobStatus',
                    type: 'GET',
                    data: { jobId: response.jobId },
                    success: function (statusResponse) {
                        if (statusResponse.isCompleted) {
                            clearInterval(pollInterval);
                            alert("任务已完成!");
                        }
                    }
                });
            }, 5000);
        }
    }
});

方案三:利用Hangfire延续任务(适合复杂任务链)

如果你的任务有依赖或者需要在完成后执行额外逻辑,可以用Hangfire的延续任务,把通知逻辑放到延续任务里:

public ActionResult RunMedia(int ID)
{
    var userId = User.Identity.GetUserId();
    var jobId = BackgroundJob.Enqueue<CrawlerSearchRequestModel>(x => x.StoreMedia(ID, "NaturalPerson"));
    
    // 添加延续任务,原任务完成后执行通知逻辑
    BackgroundJob.ContinueWith(jobId, () => SendTaskCompleteNotification(userId, $"任务ID {ID} 完成"));
    
    return Json(new { success = true }, JsonRequestBehavior.AllowGet);
}

private void SendTaskCompleteNotification(string userId, string message)
{
    var hubContext = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();
    hubContext.Clients.User(userId).receiveTaskComplete(message);
}

内容的提问来源于stack exchange,提问作者Tebogo Langa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:11:44