当使用ASP.NET和SignalR实现分布式应用程序时,可以结合Redis来实现服务端和客户端之间的通信。SignalR是一个强大的实时通信库,可帮助构建实时Web应用程序,而Redis则是一个高性能的键值存储数据库,也可以用作消息代理。
一、安装配置SignalR和Redis
在ASP.NET应用程序中,使用NuGet包管理器安装SignalR和Redis相关的库。SignalR提供了在服务器和客户端之间建立实时连接的功能,而Redis则用于处理消息的传递和分发。
NuGet: Microsoft.AspNetCore.SignalR.StackExchangeRedis
1、配置Redis连接
在应用程序的appsettings.json文件中添加Redis连接配置。示例如下:
{
"Redis": {
"ConnectionString": "localhost:6379"
}
}
2、配置SignalR服务
在Startup.cs或者Program.cs文件中添加SignalR服务配置。示例如下
builder.Services.AddSignalR().AddStackExchangeRedis(Configuration.GetConnectionString("Redis:ConnectionString"), options =>
{
//添加一个通道前缀,使多个应用可以共享同一 Redis 实例
options.Configuration.ChannelPrefix = "MyApp";
});
-
如果为多个 SignalR 应用使用一个 Redis 服务器,请为每个 SignalR 应用使用不同的通道前缀。
设置一个通道前缀会将一个 SignalR 应用与使用不同通道前缀的其他应用相隔开。 如果未分配不同的前缀,从一个应用发送到其所有客户端的消息则将转到所有将 Redis 服务器用作底板的应用的所有客户端。
3、配置SignalR后端端点
YourHub为自定义实现的Hub
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<YourHubClass>("/msghub"); // 这里指定你的 Hub 类型和终端点路径
});
二、创建一个SignalR的Hub类
此类继承自 SignalRHub。 Hub
类管理连接、组和消息,在该类中,可以定义方法,用于处理来自客户端的消息,并将其发送给指定的群组或者用户
using Microsoft.AspNetCore.SignalR;
using System.Net.WebSockets;
namespace YourNameSpace
{
public class YourHubClass : Hub
{
/// <summary>
/// 加入群组
/// </summary>
/// <param name="groupName"></param>
/// <returns></returns>
public async Task JoinGroup(string groupName)
{
await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
}
/// <summary>
/// 退出群组
/// </summary>
/// <param name="groupName"></param>
/// <returns></returns>
public async Task LeaveGroup(string groupName)
{
await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
}
/// <summary>
/// 给指定群组推送消息
/// </summary>
/// <param name="groupName"></param>
/// <param name="message"></param>
/// <returns></returns>
public async Task SendMessageToGroup(string groupName, string message)
{
await Clients.Group(groupName).SendAsync("ReceiveMessage", message);
}
/// <summary>
/// 给指定用户推送消息
/// </summary>
/// <param name="user"></param>
/// <param name="message"></param>
/// <returns></returns>
public async Task SendMessage(string user, string message)
{
await Clients.Client(user).SendAsync("ReceiveMessage", user, message);
}
public override async Task OnConnectedAsync()
{
await base.OnConnectedAsync();
// 在客户端连接成功后,你可以执行一些初始化操作
var cid = Context.ConnectionId;
//向指定用户发送消息
await Clients.Client(cid).SendAsync("ReceiveMessage", "连接成功");
}
public override async Task OnDisconnectedAsync(Exception exception)
{
// 在客户端断开连接后,你可以执行一些清理操作
// ...
await base.OnDisconnectedAsync(exception);
}
}
}
三、实现控制器推送消息
此示例简单实现了推送指定群组和指定用户的接口
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
namespace Demo.Controllers
{
[ApiController]
[Route("[controller]")]
public class YourController : ControllerBase
{
private readonly IHubContext<YourHubClass> _hubContext;
public YourController (IHubContext<YourHubClass> hubContext)
{
_hubContext = hubContext;
}
[HttpPost("SendMessageToGroup")]
public async Task<IActionResult> SendMessageToGroup([FromBody] MessageModel message)
{
await _hubContext.Clients.Group(message.GroupName).SendAsync("ReceiveMessage", message.Content);
return Ok();
}
[HttpPost("SendMessageToUser")]
public async Task<IActionResult> SendMessageToUser([FromBody] User message)
{
await _hubContext.Clients.Client(message.user).SendAsync("ReceiveMessage",message.Content);
return Ok();
}
public class MessageModel
{
public string GroupName { get; set; }
public string Content { get; set; }
}
public class User
{
public string user { get; set; }
public string Content { get; set; }
}
}
}
四、客户端连接SignalR
此示例为vue3,简单实现了加入群组并接收消息的功能。注意跨域问题,跨域的处理方法,微软官方文档也十分详细,这里不再展开。
需要导入@microsoft/signalr包
pnpm i @microsoft/signalr
<template></template>
<script setup lang="ts">
import * as signalR from "@microsoft/signalr";
const connection = new signalR.HubConnectionBuilder()
.withUrl("http://localhost:5234/msghub")//跨域需要使用绝对地址
.build();
connection
.start()
.then((msg) => {
console.log(msg);
// 连接成功
connection.invoke("JoinGroup", "dse").catch(function (err) {
console.error(err);
});
})
.catch(function (err) {
console.error(err);
});
// 接收消息
connection.on("ReceiveMessage", function (message) {
console.log("Received message: " + message);
});
// 发送消息
// function sendMessageToGroup(message) {
// connection
// .invoke("SendMessageToGroup", groupName, message)
// .catch(function (err) {
// console.error(err);
// });
// }
</script>
<style scoped></style>