asp.net core 使用 signalR(一)

Intro

SignalR 是什么?

ASP.NET Core SignalR 是一个开源代码库,它简化了向应用添加实时 Web 功能的过程。实时 Web 功能使服务器端代码能够即时将内容推送到客户端。

SignalR 的适用对象:

  • 需要来自服务器的高频率更新的应用。例如:游戏、社交网络、投票、拍卖、地图和 GPS 应用。

  • 仪表板和监视应用。示例包括公司仪表板、销售状态即时更新或行程警示。

  • 协作应用。协作应用的示例包括白板应用和团队会议软件。

  • 需要通知的应用。社交网络、电子邮件、聊天、游戏、行程警示以及许多其他应用都使用通知。

SignalR 提供了一个用于创建服务器到客户端远程过程调用(RPC)的 API。RPC 通过服务器端 .NET Core 代码调用客户端上的 JavaScript 函数。

以下是 ASP.NET Core SignalR 的一些功能:


  • 自动管理连接。



  • 同时向所有连接的客户端发送消息。例如,聊天室。



  • 将消息发送到特定的客户端或客户端组。



  • 扩展以处理增加的流量。


传输

SignalR 支持几种方法用于处理实时通信:


  • WebSockets



  • 服务器发送事件



  • 长轮询

    SignalR 会从服务器和客户端支持的功能中自动选择最佳传输方法


最近我们在做一个对战的小游戏,类似于之前比较火的答题应用,使用 websocket 来实现客户端和服务器端的通信,服务器端使用的 SignalR

SignR 基本使用

服务注册

服务配置如下:

services.AddSignalR(options =>    {        options.HandshakeTimeout = TimeSpan.FromSeconds(3);        options.KeepAliveInterval = TimeSpan.FromSeconds(10);    })    // JSON 序列化配置    .AddJsonProtocol(options =>    {        options.PayloadSerializerSettings.ContractResolver = new DefaultContractResolver();        options.PayloadSerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;        options.PayloadSerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;        options.PayloadSerializerSettings.NullValueHandling = NullValueHandling.Ignore;    });

认证方式配置

默认的 Token 是从请求头 Authorization 中获取的,而 signalr 请求服务器端的时候是放在请求地址的 query string access-token 里面的,所以我们要配置从请求头中获取或者从 QueryString 里获取,示例配置如下:

  1. services.AddAuthentication(options =>

  2.    {

  3.        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;

  4.        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

  5.        options.DefaultForbidScheme = JwtBearerDefaults.AuthenticationScheme;

  6.    })

  7.    .AddIdentityServerAuthentication(options =>

  8.    {

  9.        options.Authority = Configuration["Authorization:Authority"];

  10.        options.RequireHttpsMetadata = false;


  11.        options.TokenRetriever = request =>

  12.        {

  13.            var token = TokenRetrieval.FromAuthorizationHeader()(request);

  14.            if (string.IsNullOrWhiteSpace(token))

  15.            {

  16.                token = TokenRetrieval.FromQueryString()(request);

  17.            }


  18.            return token;

  19.        };

  20.    });

Configue 配置

  1. app.UseAuthentication();


  2. app.UseSignalR(builder =>

  3. {

  4.    builder.MapHub<QuizGameHub>("/hubs/quizGame"); // 注册 Hub

  5. });


  6. app.UseMvc();

自定义 Hub

定义 Hub 契约

定义一个客户端方法的接口以实现强类型的客户端方法调用,这里客户端调用服务器端的方法也定义了一个接口来约束,示例如下:

  1. /// <summary>

  2. /// 客户端定义的方法

  3. /// </summary>

  4. public interface IQuizGameClient

  5. {

  6.    Task GameQuestionsReceived(QuizQuestion question);


  7.    Task MatchSuccess(GameInfo gameInfo);


  8.   Task GameAnswerResultReceived(CheckedUserQuizAnswerModel answer);


  9.    Task GameOver(GameResult result);

  10. }


  11. /// <summary>

  12. /// 服务器端定义的方法

  13. /// </summary>

  14. public interface IQuizGameServer

  15. {

  16.    Task<ServiceResult<IReadOnlyList<QuizGameRuleInfo>>> GetGameRules();


  17.    Task AutoMatch(int ruleId);


  18.    Task CheckQuestionAnswer(BaseQuizAnswer model, string gameId);

  19. }

定义 Hub

有了契约之后,我们就可以定义强类型的 Hub 了,示例如下:

  1. [Authorize(Policy = "bearer")]

  2. public partial class QuizGameHub : Hub<IQuizGameClient>, IQuizGameServer

  3. {


  4.    public Task<ServiceResult<IReadOnlyList<QuizGameRuleInfo>>> GetGameRules()

  5.    {

  6.        return Task.FromResult(ServiceResult.Success(QuizGameStorage.GameRuleInfos));

  7.    }


  8.    // ...


  9.    public async Task CheckQuestionAnswer(BaseQuizAnswer model, string gameId)

  10.    {

  11.        // 调用客户端方法

  12.        await Clients.User(Context.UserIdentifier)

  13.            .GameAnswerResultReceived(checkedResult); // 向指定用户发送消息

  14.    }


  15.    public async Task AutoMatch(int ruleId)

  16.    {

  17.        // ...

  18.    }

  19. }

Reference

  • https://docs.microsoft.com/en-us/aspnet/core/signalr/introduction?view=aspnetcore-2.2

  • https://docs.microsoft.com/zh-cn/aspnet/core/signalr/introduction?view=aspnetcore-2.2