1. 程式人生 > >asp.net core 使用 signalR(一)

asp.net core 使用 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

  • 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