• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
遗忘的小猪
海内存知己,天涯若比邻
博客园    首页    新随笔    联系   管理    订阅  订阅
ASP.NET Core SignalR

ASP.NET Core SignalR 是微软开发的一套基于ASP.NET Core的与Web进行实时交互的类库,它使我们的应用能够实时的把数据推送给Web客户端。

功能

  • 自动管理连接

  • 允许同时广播到所有客户端

  • 也可以广播到指定的组或者特定的客户端

  • 在Github上开源,传送门(https://github.com/aspnet/signalr)

SignalR 提供了多种连接方式,在现代化应用中,WebSocket是最佳的传输协议,在客户端无法实现WebSocket协议的时候,SignalR就会采取其他方式,比如Server-Sent或者长轮询(在ws未出现之前,我们讨论的推拉模式)

中心 Hubs

SignalR是采用中心客户端和服务器进行通讯。

中心是一种高级的管道,允许客户端和服务器之间相互调用方法。

中心通过强类型参数传递给方法,进行模型绑定

Hubs.Clients

Clients属性包含了所有的客户端连接信息,它包含了3个属性:

  • All 所有客户端

  • Caller 进行此次请求的客户端

  • Others 排除此次请求客户端的其他客户端

包含了多个方法:

  • = AllExcept 在指定的连接除外的所有连接的客户端上调用方法

  • Client 在特定连接的客户端上调用方法

  • Clients 在特定连接的客户端上调用方法

  • Group 调用指定的组中的一种对所有连接方法

  • GroupExcept 调用中指定的组,除非指定连接到的所有连接的方法

  • Groups 调用一种对多个组的连接方法

  • OthersInGroup 调用一种对一组的连接,不包括客户端调用 hub 方法方法

  • User 调用一种对与特定用户关联的所有连接方法

  • Users 调用一种对与指定的用户相关联的所有连接方法

每个属性和方法返回的对象都包含一个SendAsync方法,可以对客户端进行调用。

HubContext

可以在应用其他地方通过使用IHubContext,达到调用Hub的目的。

两种协议

  • 文本协议:JSON

  • 二进制协议:MessagePack(https://msgpack.org/)

MessagePack类似于JSON,但传输比JSON更快,数据大小比JSON更小

服务器事项

  • 创建的Hub必须继承Microsoft.AspNetCore.SignalR.Hub,Hub类已经包含了管理连接、组和发送接收消息的属性及事件

  • 在Hub中使用的方法应该尽量使用异步的方式,因为SignalR在发送和接收消息的时候使用的是异步方法。

  • 在Startup.ConfigureServices中通过services.AddSignalR对SignalR进行注册

  • 在Startup.Configure中通过app.UseSignalR方法对Hub路由进行配置

代码解析

微软官方示范(https://docs.microsoft.com/en-us/aspnet/core/tutorials/signalr?view=aspnetcore-2.1&tabs=visual-studio)中的ChatHub:

using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;
 
namespace SignalRChat.Hubs
{
    public class ChatHub : Hub
    {
        //服务端方法
        public async Task SendMessage(string user, string message)
        {
            //ReceiveMessage 为客户端方法,让所有客户端调用这个方法
            await Clients.All.SendAsync("ReceiveMessage", user, message);
        }
    }
}

 

上述代码为当收到客户端发来的SendMessage请求后(发送聊天信息),我们把消息发送到所有客户端,让他们调用自身的ReceiveMessage方法。

用户标识

通常情况下,在用户进行连接后,Connection会保存用户的用户标识,以便对特定用户进行发送消息。

可以实现IUserIdProvider来自定义获取用户的方法,例如:

public class CustomUserIdProvider : IUserIdProvider
{
    public virtual string GetUserId(HubConnectionContext connection)
    {
        return connection.User?.FindFirst(ClaimTypes.Email)?.Value;
    }
}

 

在Startup.ConfigureServices中注册:

services.AddSingleton<IUserIdProvider, CustomUserIdProvider>();

  

 

Client的方法

T All { get; } 

相当于持久连接中的 Broadcast。

T AllExcept(params string[] excludeConnectionIds);

给排除本人所有人发送消息。

T Client(string connectionId);

跟Send操作就是一样的了。

T Clients(IList<string> connectionIds);

和Send操作的重载方法一样,可以给一批指定的人发送。

T Group(string groupName, params string[] excludeConnectionIds);

给房间中的指定人发送消息: Clients.Group("room1", "asdfasdfads");

T Groups(IList<string> groupNames, params string[] excludeConnectionIds);

给房间列表中的指定人发送消息; 【天然的聊天室功能】

T User(string userId);

这个和Client是有区别的。 这个userId => this.Context.Request.User.Identity.Name 【form验证】

cookie中间件来做到singlar的身份验证。

  userId 是你自己定义的一个标识。

T Users(IList<string> userIds);

 

客户端JS使用方法

<script src="~/lib/signalr/signalr.js"></script>
    <script type="text/javascript">
        const connection = new signalR.HubConnectionBuilder()
            .withUrl("/myChatHub")
            .configureLogging(signalR.LogLevel.Information)
            .build();
        connection.start().catch(err => console.error(err.toString()));
        //定义方法使用connection.on方法来接收返回数据
        connection.on("SendMessage", (user, message) => {
            const encodedMsg = user + " 说:" + message;
            const li = document.createElement("li");
            li.textContent = encodedMsg;
            document.getElementById("messagesList").appendChild(li);
        });

        document.getElementById("sendBtn").addEventListener("click", function () {
            var user = document.getElementById('userName').value;
            var message = document.getElementById('message').value;
            //从客户端中调用在此调用之前在自定义Hub定义的SendMessage方法
            connection.invoke("SendMessage", user, message).catch(err => console.error(err.toString()));
            document.getElementById('message').value = "";
        });
</script>

  

 

posted on 2018-09-04 09:56  一杯敬明天一杯敬过往  阅读(1684)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3