一、简介
📢 SignalR的主要功能是提供服务器和客户端之间的实时通信。当连接的客户端变得可用时,服务器可以立即向其推送内容,而不是等待客户端发起请求。这种功能特别适合需要实时更新数据的应用场景,如聊天应用、实时数据分析、多人协作编辑工具等。

二、起步
🎯本文主要介绍使用 SignalR 生成实时应用的基础知识。
- 创建 Web 项目。
- 添加 SignalR 客户端库。
- 创建 SignalR 中心。
- 配置项目以使用 SignalR。
- 添加可将消息从任何客户端发送到所有连接客户端的代码。
🪁具体介绍请移步:ASP.NET Core SignalR 双工通信-CSDN博客
2.1 开发工具选择
这里使用 Visual Studio 2022 🛠️

2.2 创建 Web 应用项目
启动 Visual Studio 2022 并选择"创建新项目"。

在"创建新项目"对话框中选择"ASP.NET Core Web 应用(Razor 页面)",然后选择"下一步"。

在"配置新项目"对话框中,为"项目名称"输入 SignalRChat。 请务必将项目命名为 SignalRChat(包括匹配大写),以便命名空间与教程中的代码匹配。
选择下一步。
在"其他信息"对话框中,选择 ".NET 8.0 (长期支持)" ,然后选择"创建"。

三、添加 SignalR 客户端库
ASP.NET Core 共享框架中包含 SignalR 服务器库。 JavaScript 客户端库不会自动包含在项目中。 对于此教程,使用库管理器 (LibMan) 从 unpkg 获取客户端库。 unpkg 是一个快速的全局内容分发网络,适用于 npm 上的所有内容。
在 "解决方案资源管理器" >中,右键单击项目,然后选择 "添加" "客户端库" 。
在"添加客户端库"对话框中:
- 为"提供程序"选择 "unpkg"
- 对于"库",请输入 @microsoft/signalr@latest
- 选择 "选择特定文件" ,展开 "dist/browser" 文件夹,然后选择 signalr.js 和 signalr.min.js。
- 将"目标位置"设置为 wwwroot/js/signalr/。
- 选择"安装" 。

LibMan 创建 wwwroot/js/signalr 文件夹并将所选文件复制到该文件夹。
四、创建 SignalR 中心
中心是一个类,用作处理客户端 - 服务器通信的高级管道。
在 SignalRChat 项目文件夹中,创建 Hubs 文件夹。
在 Hubs 文件夹中,使用以下代码创建 ChatHub 类:
cs
using Microsoft.AspNetCore.SignalR;
namespace SignalRChat.Hubs
{
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
}
ChatHub 类继承自 SignalRHub。 Hub 类管理连接、组和消息。
可通过已连接客户端调用 SendMessage,以向所有客户端发送消息。 本教程后面部分将显示调用该方法的 JavaScript 客户端代码。 SignalR 代码是异步模式,可提供最大的可伸缩性。
五、配置 SignalR
必须将 SignalR 服务器配置为将 SignalR 请求传递给 SignalR。 将以下突出显示的代码添加到 Program.cs 文件。
cs
using SignalRChat.Hubs;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.MapHub<ChatHub>("/chatHub");
app.Run();
以上突出显示的代码将 SignalR 添加到 ASP.NET Core 依赖关系注入和路由系统。
六、添加 SignalR 客户端代码
使用以下代码替换 Pages/Index.cshtml 中的内容:
cs
@page
<div class="container">
<div class="row p-1">
<div class="col-1">User</div>
<div class="col-5"><input type="text" id="userInput" /></div>
</div>
<div class="row p-1">
<div class="col-1">Message</div>
<div class="col-5"><input type="text" class="w-100" id="messageInput" /></div>
</div>
<div class="row p-1">
<div class="col-6 text-end">
<input type="button" id="sendButton" value="Send Message" />
</div>
</div>
<div class="row p-1">
<div class="col-6">
<hr />
</div>
</div>
<div class="row p-1">
<div class="col-6">
<ul id="messagesList"></ul>
</div>
</div>
</div>
<script src="~/js/signalr/dist/browser/signalr.js"></script>
<script src="~/js/chat.js"></script>
前面的标记:
- 创建文本框和提交按钮。
- 使用 id="messagesList" 创建一个列表,用于显示从 SignalR 中心接收的消息。
- 包含对 SignalR 的脚本引用,并在下一步中创建 chat.js 应用代码。
在 wwwroot/js 文件夹中,使用以下代码创建 chat.js 文件:
javascript
"use strict";
var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();
//Disable the send button until connection is established.
document.getElementById("sendButton").disabled = true;
connection.on("ReceiveMessage", function (user, message) {
var li = document.createElement("li");
document.getElementById("messagesList").appendChild(li);
// We can assign user-supplied strings to an element's textContent because it
// is not interpreted as markup. If you're assigning in any other way, you
// should be aware of possible script injection concerns.
li.textContent = `${user} says ${message}`;
});
connection.start().then(function () {
document.getElementById("sendButton").disabled = false;
}).catch(function (err) {
return console.error(err.toString());
});
document.getElementById("sendButton").addEventListener("click", function (event) {
var user = document.getElementById("userInput").value;
var message = document.getElementById("messageInput").value;
connection.invoke("SendMessage", user, message).catch(function (err) {
return console.error(err.toString());
});
event.preventDefault();
});
前面的 JavaScript:
- 创建并启动连接。
- 向"提交"按钮添加一个用于向中心发送消息的处理程序。
- 向连接对象添加一个用于从中心接收消息并将其添加到列表的处理程序。
从地址栏复制 URL,打开另一个浏览器实例或选项卡,并在地址栏中粘贴该 URL。
选择任一浏览器,输入名称和消息,然后选择"发送消息"按钮。
两个页面上立即显示名称和消息。


