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
- 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