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

SignalR即时通讯​_即时通信


SignalR即时通讯​_即时通信_02


在HubClients目录下创建IChatClient接口

SignalR即时通讯​_即时通信_03


/// <summary>
/// 集线器
/// </summary>
public interface IChatClient
{
    /// <summary>
    /// 发送消息
    /// </summary>
    /// <param name="message"></param>
    /// <returns></returns>
    Task SendMessage(object message);

}


然后我们在Hubs的目录下创建ChatHub集线器。

并定义了一个SendMessage的方法向所有的用户发送消息,并对客户端连接和断开状态做了一个日志记录。

SignalR即时通讯​_Singalr_04


/// <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和随机数。

内容如下所示:

SignalR即时通讯​_Singalr_05


 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方法,加载路由路径/ChatHubChatHub处理,并设置传输的方式可以使用WebSocketsLongPolling

SignalR即时通讯​_Singalr_06


//使用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");
});



创建控制器

SignalR即时通讯​_即时通信_07


 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

SignalR即时通讯​_即时通信_08



执行完命令会生成这样一个js文件

SignalR即时通讯​_Singalr_09



在src下面新建utils这样一个文件夹

utils是一个常见的术语,它指的是工具函数或工具方法的集合。在开发Vue应用程序时,utils通常用于存放一些常用的函数或方法,以提供给代码中的不同部分使用。


然后我们在src/utils目录下编写signalR.js文件。

请修改你本地的signalr服务器的连接地址。


SignalR即时通讯​_Singalr_10


SignalR即时通讯​_即时通信_11


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的地址


SignalR即时通讯​_Singalr_12


ChatHub是你后端Program里面这个

SignalR即时通讯​_即时通信_13




然后我们在main.js下进行全局启用signalr

SignalR即时通讯​_Singalr_14

//引入signalR
import signalr from './utils/signalR'

//挂载signalr
app.config.globalProperties.$signalr = signalr.signal