基于.NET Core 3.1+Azure SignalR无服务模式实现长时任务进度上报
后端代码修改说明
首先修正现有代码的核心问题:
- SignalR Trigger绑定的Hub名称需要和协商接口、输出绑定统一为
TestHub,原代码中Trigger第一个参数错误配置为longrunningtask会导致事件无法触发 - 长时任务方法改为异步实现,避免阻塞函数线程
- 直接在长时任务方法中注入SignalR输出绑定,无需单独封装上报函数(也可保留原有上报函数按需调用)
修改后的完整后端代码如下:
using Microsoft.AspNetCore.Http; using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.Azure.WebJobs.Extensions.SignalRService; using Microsoft.Extensions.Logging; using System.Threading.Tasks; namespace AzureSignalRFunctionTest { public static class Function1 { // 协商接口,保持不变 [FunctionName("negotiate")] public static SignalRConnectionInfo Negotiate( [HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequest req, [SignalRConnectionInfo(HubName = "TestHub")] SignalRConnectionInfo connectionInfo) { return connectionInfo; } // 修正HubName为TestHub,方法改为异步Task,注入SignalR输出绑定 [FunctionName("longrunningtask")] public static async Task LongRunningTask( [SignalRTrigger("TestHub", "messages", "SendMessage")] InvocationContext invocationContext, [SignalRParameter] string message, [SignalR(HubName = "TestHub")] IAsyncCollector<SignalRMessage> signalRMessages, ILogger logger) { logger.LogInformation($"Receive {message} from {invocationContext.ConnectionId}."); // 上报任务开始 await signalRMessages.AddAsync(new SignalRMessage { ConnectionId = invocationContext.ConnectionId, Target = "reportProgress", Arguments = new[] { "任务开始,进度0%" } }); // 模拟长时任务分阶段执行 await Task.Delay(10000); await signalRMessages.AddAsync(new SignalRMessage { ConnectionId = invocationContext.ConnectionId, Target = "reportProgress", Arguments = new[] { "执行中,进度33%" } }); await Task.Delay(10000); await signalRMessages.AddAsync(new SignalRMessage { ConnectionId = invocationContext.ConnectionId, Target = "reportProgress", Arguments = new[] { "执行中,进度66%" } }); await Task.Delay(10000); // 上报任务完成 await signalRMessages.AddAsync(new SignalRMessage { ConnectionId = invocationContext.ConnectionId, Target = "reportProgress", Arguments = new[] { "任务执行完成,进度100%" } }); } // 原有上报函数可保留用于其他场景复用,按需调用即可 [FunctionName("reportprogress")] public static Task ReportProgress(string connectionId, string message, [SignalR(HubName = "TestHub")] IAsyncCollector<SignalRMessage> signalRMessages) { return signalRMessages.AddAsync( new SignalRMessage { ConnectionId = connectionId, Target = "reportProgress", Arguments = new[] { message } }); } } }
前端HTML实现代码
前端需要完成SignalR连接初始化、事件监听、触发长时任务三个逻辑,示例代码如下:
<!DOCTYPE html> <html> <head> <title>SignalR进度上报测试</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.1/signalr.min.js"></script> </head> <body> <button id="startBtn">启动长时任务</button> <div id="progressText"></div> <script> const connection = new signalR.HubConnectionBuilder() .withUrl('你的Azure Function域名/api') // 替换为你自己的Function访问域名 .build(); // 监听进度上报事件 connection.on('reportProgress', (message) => { document.getElementById('progressText').innerText = message; }); // 启动连接 connection.start() .then(() => console.log('连接成功')) .catch(err => console.error(err)); // 点击按钮触发长时任务 document.getElementById('startBtn').addEventListener('click', () => { connection.invoke('SendMessage', '测试任务') .catch(err => console.error(err)); }); </script> </body> </html>
注意事项
- Azure SignalR服务必须配置为无服务器模式,和你当前的选型一致
- .NET Core 3.1对应的SignalR扩展包请使用1.x版本(推荐1.12.0),2.x及以上版本需要.NET 6+运行时支持
- 如果你的任务运行时长超过Azure Function消费计划的最大超时时间(默认5分钟,可配置最高10分钟),建议改用Durable Functions编排长时任务,避免函数执行超时被强制终止
- Function的CORS配置需要放开你前端页面的域名,避免跨域请求失败
内容的提问来源于stack exchange,提问作者Philip Johnson
相关产品推荐
相关产品推荐

