ASP.NET MVC 5调用无服务器Azure SignalR Hub方法的实现求助
ASP.NET MVC 5集成Azure SignalR Service无服务器模式的正确连接与调用代码
问题背景
我有一个已集成ASP.NET SignalR V2的ASP.NET MVC 5应用,现在需要以无服务器模式集成Azure SignalR Service,但查阅文档后仍未找到正确的Hub方法调用或连接方式。尝试的代码中HubConnectionBuilder.WithUrl()报错,提示方法不存在,已引用Microsoft.AspNetCore.SignalR.Client。
尝试的MVC端代码
private static async void PushNotification(NotificationRequest notificationRequest, NotificationResponse notificationResponse, string signalRUrl, string authenticationType, Cookie cookie, ICredentials credentials, string accessToken, string userId, string cacheString) { if (authenticationType == "AzureSignalR") { HubConnection _connection = new HubConnectionBuilder().WithUrl(signalRUrl).Build(); } else { using (var hubConnection = new HubConnection(signalRUrl)) { IHubProxy notificationHubProxy = hubConnection.CreateHubProxy("NotificationHub"); if (authenticationType != "AzureSignalR") { ConfigureHubConnection(hubConnection, authenticationType, cookie, credentials); } try { await hubConnection.Start(); await notificationHubProxy.Invoke("Send", notificationRequest, notificationResponse); hubConnection.Stop(); } catch (Exception e) { if (hubConnection != null && !string.IsNullOrEmpty(hubConnection.ConnectionId)) { hubConnection.Stop(); } } } } }
Azure Function端Hub代码
public class NotificationHub : ServerlessHub { [FunctionName("index")] public static IActionResult GetHomePage([HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequest req, ExecutionContext context) { var path = Path.Combine(context.FunctionAppDirectory, "content", "index.html"); return new ContentResult { Content = File.ReadAllText(path), ContentType = "text/html", }; } [FunctionName("negotiate")] public static SignalRConnectionInfo Negotiate( [HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequest req, [SignalRConnectionInfo(HubName = "NotificationHub")] SignalRConnectionInfo connectionInfo) { return connectionInfo; } [Authorize] [FunctionName(nameof(Send))] public async Task Send([SignalRTrigger] InvocationContext invocationContext, NotificationRequest notificationRequest, NotificationResponse notificationResponse) { try { await Clients.Clients(notificationResponse.ConnectionIds).SendAsync("SendNotification", notificationRequest); } catch (Exception e) { Console.WriteLine(e.Message); } } [FunctionName(nameof(OnDisconnected))] public async Task OnDisconnected([SignalRTrigger] InvocationContext invocationContext, ILogger logger) { var response = await APIService.CallDisconnectedTrigger(invocationContext.ConnectionId); if (response != null && response.ErrorMessages.Any()) { string errorMessages = string.Join(", ", response.ErrorMessages); logger.LogInformation("Some error occured while disconnecting SignalR Connection. " + errorMessages); } } }
解决方案
第一步:修正NuGet包引用
确保ASP.NET MVC 5项目安装兼容.NET Framework的Microsoft.AspNetCore.SignalR.Client版本(推荐3.1.x,高版本可能不支持.NET Framework)。
场景1:MVC作为SignalR客户端直接连接Azure SignalR Service
修正PushNotification方法的Azure SignalR分支代码,需先调用negotiate端点获取连接凭证:
// 新增Negotiate响应模型 public class NegotiateResponse { public string Url { get; set; } public string AccessToken { get; set; } } // 修正后的PushNotification方法(将async void改为async Task避免异步风险) private static async Task PushNotification(NotificationRequest notificationRequest, NotificationResponse notificationResponse, string signalRNegotiateUrl, string authenticationType, Cookie cookie, ICredentials credentials, string accessToken, string userId, string cacheString) { if (authenticationType == "AzureSignalR") { // 1. 调用Azure Function的negotiate端点获取连接信息 var negotiateResponse = await new HttpClient().GetFromJsonAsync<NegotiateResponse>(signalRNegotiateUrl); // 2. 构建SignalR连接 var connection = new HubConnectionBuilder() .WithUrl(negotiateResponse.Url, options => { options.AccessTokenProvider = () => Task.FromResult(negotiateResponse.AccessToken); // 传入身份验证凭证(如果需要) if (cookie != null) options.Cookies.Add(cookie); options.Credentials = credentials; }) .Build(); try { await connection.StartAsync(); // 调用Hub中的Send方法,参数需与Function端定义匹配 await connection.InvokeAsync("Send", notificationRequest, notificationResponse); } catch (Exception e) { Console.WriteLine($"SignalR连接或调用失败:{e.Message}"); } finally { await connection.StopAsync(); await connection.DisposeAsync(); } } else { // 保留原有的SignalR V2逻辑 using (var hubConnection = new HubConnection(signalRUrl)) { IHubProxy notificationHubProxy = hubConnection.CreateHubProxy("NotificationHub"); ConfigureHubConnection(hubConnection, authenticationType, cookie, credentials); try { await hubConnection.Start(); await notificationHubProxy.Invoke("Send", notificationRequest, notificationResponse); hubConnection.Stop(); } catch (Exception e) { if (hubConnection != null && !string.IsNullOrEmpty(hubConnection.ConnectionId)) { hubConnection.Stop(); } } } } }
注意:
signalRNegotiateUrl为Azure Function的negotiate端点地址,格式如https://你的函数应用名.azurewebsites.net/api/negotiate
场景2:MVC通过HTTP调用Azure Function推送消息(无服务器模式推荐方案)
无需维护SignalR连接,直接调用Function的HTTP端点触发消息推送:
private static async Task PushNotificationViaFunction(NotificationRequest notificationRequest, NotificationResponse notificationResponse, string functionSendUrl, string accessToken) { var client = new HttpClient(); // 如果Function启用授权,添加Bearer令牌 if (!string.IsNullOrEmpty(accessToken)) { client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); } // 构造请求体 var requestBody = new { notificationRequest = notificationRequest, notificationResponse = notificationResponse }; var content = new StringContent(JsonConvert.SerializeObject(requestBody), Encoding.UTF8, "application/json"); var response = await client.PostAsync(functionSendUrl, content); if (!response.IsSuccessStatusCode) { var errorContent = await response.Content.ReadAsStringAsync(); Console.WriteLine($"调用Function失败:{errorContent}"); } }
注意:
functionSendUrl为Azure Function中Send方法的地址,格式如https://你的函数应用名.azurewebsites.net/api/Send,需安装Newtonsoft.Json包序列化请求体。
Azure Function端补充说明
- 确保应用设置中已配置
AzureSignalRConnectionString(指向你的Azure SignalR Service连接字符串) - 若无需授权,可移除
Send方法上的[Authorize]特性;若需授权,需配置对应的身份验证规则 Send方法的参数需与客户端调用时的参数完全匹配,确保消息能正确路由到目标客户端
内容的提问来源于stack exchange,提问作者Mohd Anzal
相关产品推荐
相关产品推荐

