1. 实时Web功能
SignalR 允许服务器直接推送数据到客户端,而无需客户端不断请求。实时Web功能可以用于多种场景,常见应用包括:
- 聊天应用:支持多个用户实时交流。🗨️
- 实时通知:在用户操作后立即更新界面。🔔
- 数据监控:如股票、天气、传感器数据等实时更新。📈
- 多人在线游戏:游戏状态实时同步,确保玩家间的互动。🎮
2. 服务器到客户端远程过程调用 (RPC)
SignalR 提供了一个直观的 API 让服务器调用客户端的 JavaScript 函数,这种方式称为 RPC。实现简单:
- 调用示例:
1public class MyHub : Hub
2{
3 public void SendMessage(string user, string message)
4 {
5 Clients.All.SendAsync("ReceiveMessage", user, message);
6 }
7}
8
- 上述代码在服务器上定义了一个
SendMessage
方法,与所有连接的客户端广播消息。
3. 连接管理
SignalR 提供连接管理的 API,例如:
- 连接和断开连接事件:你可以在连接和断开客户端时触发事件,便于管理在线用户的状态。
- 分组功能:可以将连接的客户端分组,允许消息只能发送到特定组,例如一个聊天房间。
4. Hubs
Hubs 是 SignalR 的核心,提供了客户端和服务器之间的通信通道。具体功能包括:
- 双向通信:允许客户端和服务器彼此调用方法。
- 强类型参数支持:通过强类型参数简化数据传输,支持模型绑定。
- 序列化方式:SignalR 支持多种消息协议,包括 JSON 和 MessagePack,后者可以提高性能。
5. 传输机制
SignalR 自动选择最佳的传输方式来建立连接,支持的传输方式包括:
- WebSockets:如果可用,则SignalR优先使用 WebSocket,因为它具有最低的延迟和最高的性能。
- Server-Sent Events:用于支持不支持 WebSockets 的浏览器。
- 长期轮询:在没有其他选项的情况下,利用传统的HTTP回调机制。
6. 扩展与灵活性
SignalR 支持多种客户端平台,不仅限于浏览器中的 JavaScript,还可以在移动设备应用、桌面应用等中使用:
- 与其他.NET框架集成:SignalR可以与 ASP.NET MVC、Web API、Blazor 等框架无缝集成。
- 授权与安全:支持身份验证和授权,确保只有经过授权的用户可以访问特定功能。
7. 可扩展性
SignalR 的架构设计考虑了可扩展性,支持在大型应用中处理大量连接,并且可以通过增加服务器或使用负载均衡器来扩展。
8. 开发与调试工具
SignalR 提供实时调试和日志记录工具,帮助开发者追踪连接状态、消息传递和性能数据。
SignalR后端项目
创建项目
下载Nuget包 Microsoft.AspNetCore.SignalR.Core
在HubClients目录下创建IChatClient接口
/// <summary>
/// 集线器
/// </summary>
public interface IChatClient
{
/// <summary>
/// 发送消息
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
Task SendMessage(object message);
}
然后我们在Hubs的目录下创建ChatHub集线器。
并定义了一个SendMessage的方法向所有的用户发送消息,并对客户端连接和断开状态做了一个日志记录。
/// <summary>
/// 集线器
/// </summary>
public class ChatHub:Hub<IChatClient>
{
ILogger<ChatHub> logger;
readonly CommonService _common;
public ChatHub(ILogger<ChatHub> logger)
{
this.logger = logger;
}
/// <summary>
/// 客户端连接服务端
/// </summary>
/// <returns></returns>
public override Task OnConnectedAsync()
{
var id = Context.ConnectionId;
logger.LogInformation($"Client ConnectionId=> [[{id}]] Already Connection Server!");
return base.OnConnectedAsync();
}
/// <summary>
/// 客户端断开连接
/// </summary>
/// <param name="exception"></param>
/// <returns></returns>
public override Task OnDisconnectedAsync(Exception? exception)
{
var id = Context.ConnectionId;
logger.LogInformation($"Client ConnectionId=> [[{id}]] Already Close Connection Server!");
return base.OnDisconnectedAsync(exception);
}
/// <summary>
/// 发送消息
/// </summary>
/// <param name="user"></param>
/// <param name="message"></param>
/// <returns></returns>
// 定义了 SendMessage 方法,客户端可以调用该方法
public async Task SendMessage(string user, string message)
{
Console.WriteLine("Have one Data!" + message);
await Clients.All.SendMessage(_common.SendMessage(message));
}
}
这里有一个CommonService它定义在HubService的目录下面,里面只有一个SendAll方法,该方法只是在原有的消息基础上添加Hello和随机数。
内容如下所示:
public class CommonService
{
/// <summary>
/// 添加Hello和随机数
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
internal object SendMessage(string data)
{
return $"Hello {new Random().Next(0, 100)} {data} ";
}
}
配置SignalR
我们可以通过AddSignalR方法来注册SignalR相关服务,并通过AddJsonProtocol启用SignalR 的 JSON 协议。
PayloadSerializerOptions是一个System.Text.JsonJsonSerializerOptions对象,PropertyNamingPolicy属性为null表示保持属性名称不变(是否区分大小写,无所谓)。
然后我们通过MapHub方法,加载路由路径/ChatHub由ChatHub处理,并设置传输的方式可以使用WebSockets与LongPolling
//使用signalR
builder.Services.AddSignalR().AddJsonProtocol(options =>
{
options.PayloadSerializerOptions.PropertyNamingPolicy = null;
});
//注入CommonService
builder.Services.AddTransient(typeof(CommonService));
app.UseRouting();
//配置跨域
app.UseCors(x => x.AllowAnyHeader().AllowAnyOrigin().AllowAnyMethod());
//配置signalR
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<ChatHub>("/ChatHub");
});
创建控制器
private readonly ILogger<MessageController> logger;
/// <summary>
/// 发送消息服务器
/// </summary>
/// <param name="logger"></param>
public MessageController(ILogger<MessageController> logger)
{
this.logger = logger;
}
/// <summary>
/// 发送消息给所有客户端
/// </summary>
/// <param name="date"></param>
/// <param name="hubContext"></param>
/// <returns></returns>
///
[HttpGet]
public async Task SendMessage(string date, [FromServices] IHubContext<ChatHub, IChatClient> hubContext)
{
var message = $"服务器消息: {date}";
await hubContext.Clients.All.SendMessage(message);
}
创建vue3项目 输入 npm install @microsoft/signalr 命令
npm install @microsoft/signalr
执行完命令会生成这样一个js文件
在src下面新建utils这样一个文件夹
utils是一个常见的术语,它指的是工具函数或工具方法的集合。在开发Vue应用程序时,utils通常用于存放一些常用的函数或方法,以提供给代码中的不同部分使用。
然后我们在src/utils目录下编写signalR.js文件。
请修改你本地的signalr服务器的连接地址。
import * as signalR from '@microsoft/signalr'
const url = 'http://localhost:54479/ChatHub'
const signal = new signalR.HubConnectionBuilder()
.withUrl(url, {
skipNegotiation: true,
transport: signalR.HttpTransportType.WebSockets
})
.configureLogging(signalR.LogLevel.Information)
.build()
signal.on('SendMessage', (res) => {
console.log(res)
})
signal.start().then(() => {
if (window.Notification) {
if (Notification.permission === 'granted') {
console.log('允许通知')
} else if (Notification.permission !== 'denied') {
console.log('需要通知权限')
Notification.requestPermission((permission) => {
console.log('权限通知', permission)
})
} else if (Notification.permission === 'denied') {
console.log('拒绝通知')
}
} else {
console.error('浏览器不支持Notification')
}
console.log('连接成功')
})
signal.onclose((err) => {
console.log('连接已经断开 执行函数onclose', err)
})
export default {
signal
}
这个地址是你后台Api的地址
ChatHub是你后端Program里面这个
然后我们在main.js下进行全局启用signalr。
//引入signalR
import signalr from './utils/signalR'
//挂载signalr
app.config.globalProperties.$signalr = signalr.signal