欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

asp.net core 使用 signalR(一)

程序员文章站 2022-05-29 10:24:16
asp.net core 使用 signalR(一) Intro SignalR 是什么? ASP.NET Core SignalR 是一个开源代码库,它简化了向应用添加实时 Web 功能的过程。 实时 Web 功能使服务器端代码能够即时将内容推送到客户端。 SignalR 的适用对象: 需要来自服 ......

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 里获取,示例配置如下:

services.addauthentication(options =>
    {
        options.defaultauthenticatescheme = jwtbearerdefaults.authenticationscheme;
        options.defaultchallengescheme = jwtbearerdefaults.authenticationscheme;
        options.defaultforbidscheme = jwtbearerdefaults.authenticationscheme;
    })
    .addidentityserverauthentication(options =>
    {
        options.authority = configuration["authorization:authority"];
        options.requirehttpsmetadata = false;

        options.tokenretriever = request =>
        {
            var token = tokenretrieval.fromauthorizationheader()(request);
            if (string.isnullorwhitespace(token))
            {
                token = tokenretrieval.fromquerystring()(request);
            }

            return token;
        };
    });

configue 配置

app.useauthentication();

app.usesignalr(builder =>
{
    builder.maphub<quizgamehub>("/hubs/quizgame"); // 注册 hub
});

app.usemvc();

自定义 hub

定义 hub 契约

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

/// <summary>
/// 客户端定义的方法
/// </summary>
public interface iquizgameclient
{
    task gamequestionsreceived(quizquestion question);

    task matchsuccess(gameinfo gameinfo);

   task gameanswerresultreceived(checkeduserquizanswermodel answer);

    task gameover(gameresult result);
}

/// <summary>
/// 服务器端定义的方法
/// </summary>
public interface iquizgameserver
{
    task<serviceresult<ireadonlylist<quizgameruleinfo>>> getgamerules();

    task automatch(int ruleid);

    task checkquestionanswer(basequizanswer model, string gameid);
}

定义 hub

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

[authorize(policy = "bearer")]
public partial class quizgamehub : hub<iquizgameclient>, iquizgameserver
{

    public task<serviceresult<ireadonlylist<quizgameruleinfo>>> getgamerules()
    {
        return task.fromresult(serviceresult.success(quizgamestorage.gameruleinfos));
    }
    
    // ...

    public async task checkquestionanswer(basequizanswer model, string gameid)
    {
        // 调用客户端方法
        await clients.user(context.useridentifier)
            .gameanswerresultreceived(checkedresult); // 向指定用户发送消息
    }
    
    public async task automatch(int ruleid)
    {
        // ...
    }
}

reference