9.2 SignalR (实时通信)


文档摘要

9.2 SignalR (实时通信) 9.2 SignalR (实时通信) SignalR 是一个 ASP.NET 库,简化了向 ASP.NET 应用程序添加实时 Web 功能的过程。实时 Web 功能是指服务器可以将内容推送到连接的客户端,而无需客户端持续轮询服务器。SignalR 解决了构建此类功能的复杂性,例如管理持久连接、处理不同的浏览器和传输机制以及处理服务器端扩展。 9.2.1 SignalR 的优势 简化实时开发: SignalR 抽象了底层传输细节,使开发人员能够专注于应用程序的逻辑。 多种传输方式支持: SignalR 自动选择最佳传输方式,包括 WebSockets、Server-Sent Events (SSE) 和 Long Polling。

9.2 SignalR (实时通信)

9.2 SignalR (实时通信)

SignalR 是一个 ASP.NET 库,简化了向 ASP.NET 应用程序添加实时 Web 功能的过程。实时 Web 功能是指服务器可以将内容推送到连接的客户端,而无需客户端持续轮询服务器。SignalR 解决了构建此类功能的复杂性,例如管理持久连接、处理不同的浏览器和传输机制以及处理服务器端扩展。

9.2.1 SignalR 的优势

  • 简化实时开发: SignalR 抽象了底层传输细节,使开发人员能够专注于应用程序的逻辑。

  • 多种传输方式支持: SignalR 自动选择最佳传输方式,包括 WebSockets、Server-Sent Events (SSE) 和 Long Polling。它会根据客户端和服务器的能力进行协商。

  • 双向通信: SignalR 支持服务器向客户端推送数据,以及客户端向服务器发送数据。

  • 扩展性: SignalR 可以扩展以支持大量的并发连接,例如使用 Redis Backplane。

  • 易于集成: SignalR 可以轻松集成到现有的 ASP.NET 应用程序中。

9.2.2 SignalR 的核心概念

  • Hubs: Hub 是 SignalR 的核心组件。它是一个服务器端类,客户端可以直接调用其方法。Hub 充当服务器和客户端之间的管道,允许双方相互通信。

  • Connections: Connection 代表客户端和 SignalR 服务器之间的持久连接。SignalR 管理这些连接,并在连接断开时尝试重新建立连接。

  • Transport: Transport 是 SignalR 用于在客户端和服务器之间发送数据的底层机制。SignalR 自动选择最佳传输方式。

  • Groups: Group 允许将连接组织成逻辑单元。服务器可以向特定组发送消息,而不是向所有连接的客户端发送消息。

9.2.3 SignalR 的工作原理

SignalR 的工作原理可以概括为以下步骤:

  1. 客户端连接: 客户端使用 SignalR 客户端库建立与 SignalR 服务器的连接。

  2. 传输协商: SignalR 客户端和服务器协商最佳传输方式。

  3. 持久连接: 建立持久连接后,客户端可以调用 Hub 上的方法,服务器也可以向客户端推送消息。

  4. 消息传递: 消息在客户端和服务器之间以 JSON 格式进行传递。

  5. 连接管理: SignalR 管理连接的生命周期,并在连接断开时尝试重新建立连接。

以下是一个简单的流程图,展示了 SignalR 的基本工作流程:

graph TD A[Client] --> B(SignalR Server); B --> C{Transport Negotiation}; C -- WebSockets --> D[Persistent Connection]; C -- Server-Sent Events --> D; C -- Long Polling --> D; D --> E{Message Exchange}; E -- Client to Server --> B; E -- Server to Client --> A;

9.2.4 SignalR 代码实践

以下是一些 SignalR 的代码示例,展示了如何使用 SignalR 构建实时应用程序。

9.2.4.1 创建 SignalR Hub

首先,需要创建一个 Hub 类。Hub 类继承自 Microsoft.AspNetCore.SignalR.Hub 类,并包含客户端可以调用的方法。

using Microsoft.AspNetCore.SignalR; using System.Threading.Tasks; public class ChatHub : Hub { public async Task SendMessage(string user, string message) { await Clients.All.SendAsync("ReceiveMessage", user, message); } public async Task JoinGroup(string groupName) { await Groups.AddToGroupAsync(Context.ConnectionId, groupName); await Clients.Group(groupName).SendAsync("Send", $"{Context.ConnectionId} has joined the group {groupName}."); } public async Task LeaveGroup(string groupName) { await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName); await Clients.Group(groupName).SendAsync("Send", $"{Context.ConnectionId} has left the group {groupName}."); } }
  • SendMessage 方法:接收用户名和消息,并将消息发送给所有连接的客户端。

  • JoinGroup 方法:将客户端添加到指定的组,并向该组发送一条消息。

  • LeaveGroup 方法:将客户端从指定的组中移除,并向该组发送一条消息。

  • Clients.All.SendAsync:将消息发送给所有连接的客户端。

  • Clients.Group(groupName).SendAsync:将消息发送给指定组中的所有客户端。

  • Context.ConnectionId:获取当前客户端的连接 ID。

9.2.4.2 配置 SignalR 服务

Startup.cs 文件中,需要配置 SignalR 服务。

public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); services.AddSignalR(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); endpoints.MapHub<ChatHub>("/chatHub"); }); }
  • services.AddSignalR():将 SignalR 服务添加到依赖注入容器中。

  • endpoints.MapHub<ChatHub>("/chatHub"):将 ChatHub 映射到 /chatHub 路由。

9.2.4.3 创建 SignalR 客户端

在客户端,需要使用 SignalR 客户端库建立与 SignalR 服务器的连接,并调用 Hub 上的方法。

const connection = new signalR.HubConnectionBuilder() .withUrl("/chatHub") .configureLogging(signalR.LogLevel.Information) .build(); async function start() { try { await connection.start(); console.log("SignalR Connected."); } catch (err) { console.log(err); setTimeout(() => start(), 5000); } }; connection.onclose(async () => { await start(); }); // Receive messages connection.on("ReceiveMessage", (user, message) => { const li = document.createElement("li"); li.textContent = `${user} says ${message}`; document.getElementById("messagesList").appendChild(li); }); // Send Message document.getElementById("sendButton").addEventListener("click", async (event) => { const user = document.getElementById("userInput").value; const message = document.getElementById("messageInput").value; try { await connection.invoke("SendMessage", user, message); } catch (err) { console.error(err); } event.preventDefault(); }); // Join Group document.getElementById("joinGroupButton").addEventListener("click", async (event) => { const groupName = document.getElementById("groupNameInput").value; try { await connection.invoke("JoinGroup", groupName); } catch (err) { console.error(err); } event.preventDefault(); }); // Leave Group document.getElementById("leaveGroupButton").addEventListener("click", async (event) => { const groupName = document.getElementById("groupNameInput").value; try { await connection.invoke("LeaveGroup", groupName); } catch (err) { console.error(err); } event.preventDefault(); }); start();
  • new signalR.HubConnectionBuilder().withUrl("/chatHub").build():创建一个与 /chatHub 路由的 SignalR 连接。

  • connection.start():启动连接。

  • connection.on("ReceiveMessage", ...):注册一个回调函数,当服务器向客户端发送 ReceiveMessage 消息时,该回调函数将被调用。

  • connection.invoke("SendMessage", user, message):调用服务器端 ChatHub 上的 SendMessage 方法。

9.2.4.4 HTML 客户端界面

<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>SignalR Chat</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> </head> <body> <div class="container"> <h1>SignalR Chat</h1> <div class="row"> <div class="col-md-12"> <ul id="messagesList"></ul> </div> </div> <div class="row"> <div class="col-md-4"> <input type="text" id="userInput" class="form-control" placeholder="User Name" /> </div> <div class="col-md-4"> <input type="text" id="messageInput" class="form-control" placeholder="Message" /> </div> <div class="col-md-4"> <button type="button" id="sendButton" class="btn btn-primary">Send</button> </div> </div> <hr /> <div class="row"> <div class="col-md-4"> <input type="text" id="groupNameInput" class="form-control" placeholder="Group Name" /> </div> <div class="col-md-4"> <button type="button" id="joinGroupButton" class="btn btn-success">Join Group</button> </div> <div class="col-md-4"> <button type="button" id="leaveGroupButton" class="btn btn-danger">Leave Group</button> </div> </div> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.1/signalr.js"></script> <script src="js/chat.js"></script> </body> </html>

这个 HTML 代码创建了一个简单的聊天界面,包括:

  • 一个用于显示消息的 <ul> 元素 (messagesList)。

  • 一个用于输入用户名的 <input> 元素 (userInput)。

  • 一个用于输入消息的 <input> 元素 (messageInput)。

  • 一个用于发送消息的 <button> 元素 (sendButton)。

  • 一个用于输入组名的 <input> 元素 (groupNameInput)。

  • 一个用于加入组的 <button> 元素 (joinGroupButton)。

  • 一个用于离开组的 <button> 元素 (leaveGroupButton)。

9.2.4.5 代码详解

  • Hub 类: Hub 类是 SignalR 应用的核心。它定义了客户端可以调用的方法,以及服务器可以推送给客户端的消息。

  • ConfigureServices 方法: AddSignalR() 方法将 SignalR 服务添加到 ASP.NET Core 依赖注入容器中。

  • Configure 方法: MapHub<ChatHub>("/chatHub") 方法将 ChatHub 类映射到指定的 URL 路径。客户端将使用此 URL 路径建立与 Hub 的连接。

  • SignalR 客户端库: SignalR 客户端库提供了一组 API,用于建立与 SignalR 服务器的连接,调用 Hub 方法,以及接收服务器推送的消息。

  • HubConnectionBuilder: HubConnectionBuilder 类用于创建 HubConnection 对象,该对象代表与 SignalR 服务器的连接。

  • connection.start(): 启动与 SignalR 服务器的连接。

  • connection.on(): 注册一个回调函数,当服务器向客户端发送指定的消息时,该回调函数将被调用。

  • connection.invoke(): 调用服务器端 Hub 类上的方法。

9.2.5 SignalR 的高级特性

  • 身份验证和授权: SignalR 支持身份验证和授权,可以使用 ASP.NET Core 的身份验证和授权机制来保护 Hub 方法。

  • 错误处理: SignalR 提供了错误处理机制,可以捕获 Hub 方法中的异常,并将错误信息发送给客户端。

  • 诊断: SignalR 提供了诊断功能,可以跟踪连接、消息和传输的性能。

  • 扩展性: SignalR 可以扩展以支持大量的并发连接,例如使用 Redis Backplane。

9.2.6 SignalR 的应用场景

  • 聊天应用程序: SignalR 可以用于构建实时聊天应用程序,允许用户实时发送和接收消息。

  • 在线游戏: SignalR 可以用于构建在线游戏,允许玩家实时互动。

  • 监控仪表板: SignalR 可以用于构建监控仪表板,实时显示服务器和应用程序的性能指标。

  • 协作应用程序: SignalR 可以用于构建协作应用程序,允许多个用户同时编辑文档或进行其他协作活动。

  • 通知系统: SignalR 可以用于构建实时通知系统,例如在社交媒体应用中显示新消息或好友请求。

总而言之,SignalR 是一个功能强大的库,可以简化在 ASP.NET 应用程序中构建实时 Web 功能的过程。通过抽象底层传输细节并提供易于使用的 API,SignalR 使开发人员能够专注于构建出色的实时用户体验。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U