ASP.NET Core SignalR:集线器Hubs

  • 2019 年 10 月 3 日
  • 笔记

一、什么是集线器hubs

  通过SignalR的集线器hubs中定义的方法,服务器可以调用连接中的客户端定义的方法,而客户端也可以调用服务器端集线器中定义的方法。SignalR负责实现了客户端和服务器之间的实时通信。

二、配置SignalR的hubs

  SignalR通过在Startup.ConfigureServices中调用services.AddSignalR()来配置中间件服务。

services.AddSignalR()

  将 SignalR 功能添加到 ASP.NET Core 应用程序时,通过在Startup.Configure方法中调用app.UseSignalR来设置 SignalR 路由。

app.UseSignalR(routes =>  {    routes.MapHub<BaseHub>("/Hub");  });

 三、创建集线器Hubs

  通过继承Hub类来创建集线器类,并添加public修饰的方法。可以通过特性[HubMethodName]来修改方法的名称。

public async Task SendMessage(string user,string message)  {      await Clients.All.SendAsync("ReceiveMessage", user, message);  }

  注意:   

  • 客户端只能调用集线器类中定义的public的方法。
  • 每次客户端访问服务器的集线器类的时候都是在新的对象实例上运行的,所以不能将状态存储在集线器类中。
  • SignalR的代码是异步模式的,所以集线器中的方法也都是异步的。

四、参数和返回类型

  将集线器类和客户端接收代码改为如下所示:

public class paramsEntity  {      public string user { get; set; }      public string message { get; set; }  }    public async Task SendMessage(paramsEntity param)  {      await Clients.All.SendAsync("ReceiveMessage", param);  }

//接收服务器端消息ReceiveMessage的处理程序  connection.on("ReceiveMessage", function (param) {    if (param.user)      $('#content').append(param.user + ":");    if (param.message)      $('#content').append(param.message + ":");  });    //发送消息至服务器端SendMessage方法  connection.invoke("SendMessage", { user, message }).catch(function (err) {    return console.error(err.toString());  });

  通过运行可以发现,SignalR会通过序列化和反序列化来处理复杂的参数和返回类型。如果客户端传递的参数和服务器端不一致会导致方法无法被匹配到而报错以下错误。

Microsoft.AspNetCore.SignalR.HubException: Failed to invoke 'SendMessage' due to an error on the server.

  所以使用自定义对象作为参数更加的灵活多变。

五、Hub的对象

  1、Context

  Hub类具有一个上下文Context,包含连接中的以下属性以及方法。

属性 描述
ConnectionId 获取由 SignalR 分配的连接的唯一 ID。每个连接都有一个连接 ID
UserIdentifier 获取用户标识符。 默认情况下,SignalR 使用ClaimTypes.NameIdentifier与连接ClaimsPrincipal关联的作为用户标识符。
User 获取与ClaimsPrincipal当前用户关联的。
Items 获取可用于在此连接的范围内共享数据的键/值集合。数据可以存储在此集合中,它将在不同的集线器方法调用中持久保存。
Features 获取连接上的可用功能的集合。目前,在大多数情况下不需要此集合,因此不会对其进行详细介绍。
ConnectionAborted 获取一个CancellationToken,它将在连接中止时通知。
方法 描述
GetHttpContext 返回连接HttpContextnull,如果连接不与 HTTP 请求关联,则为。对于 HTTP 连接,可以使用此方法来获取 HTTP 标头和查询字符串等信息。
Abort 中止连接。

2、Clients

  Hub类的Clients属性包含服务器和客户端之间通信的方法和属性。

属性 描述
All 在所有连接的客户端上调用方法
Caller 在调用集线器方法的客户端上调用方法
Others 在所有连接的客户端上调用方法,但调用方法的客户端除外
方法 描述
AllExcept 在所有连接的客户端(指定的连接除外)上调用方法
Client 在特定连接的客户端上调用方法
Clients 在多个特定连接的客户端上调用方法
Group 对指定组中的所有连接调用方法
GroupExcept 对指定组中的所有连接调用方法,指定的连接除外 
Groups 在多组连接上调用方法
OthersInGroup 对一组连接调用方法,而不包括调用该集线器方法的客户端
User 对与特定用户关联的所有连接调用方法
Users 对与指定用户相关联的所有连接调用方法

  表中的每个属性或方法都返回一个SendAsync包含方法的对象。 SendAsync方法允许你提供要调用的客户端方法的名称和参数。

六、强类型的hub

  使用SendAsync的时候需要传入字符串来指定调用客户端的方法,这就会导致拼写错误等问题引发程序运行错误。

  通过使用强类型Hub<T>将客户端的方法约定为接口,这样Hub的Clients的将会禁用Sendasync方法,而只能调用我们约定的接口方法。

    public interface IHub      {          Task ReceiveMessage(string user, string message);          Task ReceiveMessage(string message);      }

    public class BaseHub : Hub<IHub>      {          public async Task SendMessage(string user, string message)          {              await Clients.All.ReceiveMessage(user, message);          }      }

 七、处理连接事件

  SignalR的hub提供OnConnectedAsyncOnDisconnectedAsync虚拟方法来管理和跟踪连接。 重写OnConnectedAsync虚拟方法,以便在客户端连接到集线器时执行操作,如将其添加到组。

public override async Task OnConnectedAsync()  {      await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");      await base.OnConnectedAsync();  }

  重写OnDisconnectedAsync虚拟方法,以便在客户端断开连接时执行操作。 如果客户端故意断开连接(例如connection.stop(),通过调用),则exception参数将为null。 但是,如果客户端由于错误(例如网络故障)而断开连接,则exception参数将包含描述失败的异常。

public override async Task OnDisconnectedAsync(Exception exception)  {      await Groups.RemoveFromGroupAsync(Context.ConnectionId, "SignalR Users");      await base.OnDisconnectedAsync(exception);  }