WebSocket Client连接AspNetCore SignalR Json Hub

时间:2021-09-29 00:13:26

突然有个需求,需要使用普通的websocket客户端去连接SignalR服务器。

因为使用的是.net core 版的signalr,目前对于使用非signalr客户端连接的中文文档几乎为0,在gayhub折腾几天总算折腾出来了。

 

首先,在startup.cs的ConfigureServices方法中添加signalr配置

services.AddSignalR(options =>
            {
                // Faster pings for testing
                options.KeepAliveInterval = TimeSpan.FromSeconds(5);
            }).AddJsonProtocol(options =>
            {
                //options.PayloadSerializerSettings.Converters.Add(JsonConver);
                //the next settings are important in order to serialize and deserialize date times as is and not convert time zones
                options.PayloadSerializerSettings.Converters.Add(new IsoDateTimeConverter());
                options.PayloadSerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Unspecified;
                options.PayloadSerializerSettings.DateParseHandling = DateParseHandling.DateTimeOffset;
            });

因为使用的微信小程序的websocket,而且在微信小程序的websocket请求头中加入了一个字段

Sec-WebSocket-Protocol: protocol1
要求服务器在返回的时候也需要在头中加入这个。
在startup.cs的Configure方法中配置Hub时加入子协议。
app.UseSignalR(routes =>
            {
                routes.MapHub<AbpCommonHub>("/signalr");
                routes.MapHub<Chat.SignalR.Chat>("/chat", options =>
                    options.WebSockets.SubProtocol = "protocol1");
            });

 

然后是Chat.cs.  因为我用的是Abp.AspNetCore.SignalR,所以在写法上会略微和aspnetcore.signalr有区别

using Abp.Dependency;
using Abp.Runtime.Session;
using Castle.Core.Logging;
using Microsoft.AspNetCore.SignalR;
using System;
using System.Threading.Tasks;
public
class Chat : Hub, ITransientDependency { public IAbpSession AbpSession { get; set; } public ILogger Logger { get; set; } public ChatNoAnnoy() { AbpSession = NullAbpSession.Instance; Logger = NullLogger.Instance; } public async Task SendMessage(string message) { await Clients.All.SendAsync("getMessage", string.Format("User {0}: {1}", AbpSession.UserId, message)); } public override async Task OnConnectedAsync() { await base.OnConnectedAsync(); Logger.Debug("A client connected to MyChatHub: " + Context.ConnectionId); } public override async Task OnDisconnectedAsync(Exception exception) { await base.OnDisconnectedAsync(exception); Logger.Debug("A client disconnected from MyChatHub: " + Context.ConnectionId); } public void log(string arg) { Logger.Info("client send:" + arg); }

 

这样在浏览器输入http://myhost/chat (myhost换成自己的域名  或者是ip:端口) 

出现  Connection ID required 就说明signalr启动成功了。

 

然后是客户端代码。这里我使用的是ClientWebSocket

 1 ClientWebSocket client = new ClientWebSocket();
 2 client.Options.AddSubProtocol("protocol1");
 3 wait client.ConnectAsync(new Uri(BaseUrl), CancellationToken.None);
 4 Console.WriteLine("Connect success");
 5 
 6 await client.SendAsync(new ArraySegment<byte>(AddSeparator(Encoding.UTF8.GetBytes(@"{""protocol"":""json"", ""version"":1}")))
 7       , WebSocketMessageType.Text, true, CancellationToken.None);//发送握手包
 8 Console.WriteLine("Send success");
 9 var bytes = Encoding.UTF8.GetBytes(@"{
10     ""type"": 1,
11   ""invocationId"":""123"",
12     ""target"": ""log"",
13     ""arguments"": [
14         ""Test Message""
15     ]
16     }"")");//发送远程调用 log方法
17  await client.SendAsync(new ArraySegment<byte>(AddSeparator(bytes)), WebSocketMessageType.Text, true, CancellationToken.None);
18  var buffer = new ArraySegment<byte>(new byte[1024]);
19  while (true)
20  {
21      await client.ReceiveAsync(buffer, CancellationToken.None);
22      Console.WriteLine(Encoding.UTF8.GetString(RemoveSeparator(buffer.ToArray())));
23  }

添加和删除分隔符方法

private static byte[] AddSeparator(byte[] data)
{
    List<byte> t = new List<byte>(data) { 0x1e };//0x1e record separator
    return t.ToArray();
}
private static byte[] RemoveSeparator(byte[] data)
{
    List<byte> t = new List<byte>(data);
    t.Remove(0x1e);
    return t.ToArray();
}

然后就能在服务器日志中查看到log方法调用后的结果

WebSocket Client连接AspNetCore SignalR Json Hub