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