Framework4.0连接AspNetCore SignalR Hub 最近有项目要使用AspNetCore重构,其中包含了AspNetCore SignalR Hub服务,而我们的桌面端程序使用的还是Framework4.0版本开发的(因为依然有客户在使用XP的系统,而XP系统最高支持到Framework4.0版本),微软的Microsoft.AspNet.SignalR.Client在Framework4.0下只是1x版本,连2x版本都连接不上,再加上Microsoft.AspNet.SignalR.Client和Microsoft.AspNetCore.SignalR.Client差异较大,Microsoft.AspNet.SignalR.Client无法连接AspNetCore版的SignalR服务。
经过各种查询资料,折腾了一天,始终没找到答案。于是换个思路,既然SignalR服务支持WebSocket模式,那么使用WebSocket客户端应该可以连接吧。换个思路继续搜索资料,结果依然非常非常的少,最终仅找到一篇使用微软ClientWebsocket类来连接AspNetCore SignalR Hub服务的文章,链接 https://www.cnblogs.com/turingguo/p/9072865.html 这里非常感谢这位老兄。
然而当我打开微软官方关于ClientWebsocket类的资料页面并看到底部,心里真的是万马奔腾,因为最低只支持到Framework4.5,4.0下不能用。继续寻找Framework4.0下可用的Websocket Client,最终找到了websocket-sharp组件,链接 https://github.com/sta/websocket-sharp ,通过Nuget添加时需注意,要添加名称为WebSocketSharpFork的包。
1、首先是服务端实现,这里使用的是.NET Core 3.1版本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 public class MsgHub : Hub { private static IDictionary<string, string> clientDic = new Dictionary<string, string>(); private readonly ILogger<MsgHub> _logger; public MsgHub(ILogger<MsgHub> logger) { _logger = logger; } [HubMethodName("SendMessage")] public async Task SendMessageAsync(string message) { _logger.LogDebug($"客户端说:{message}"); clientDic.TryGetValue(Context.ConnectionId, out var userId); await Clients.All.SendAsync("ReceiveMessage", $"来自用户{userId}的消息:{message}"); } public override async Task OnConnectedAsync() { string userId = Context.GetHttpContext().Request.Query["uid"].FirstOrDefault(); if (string.IsNullOrEmpty(userId)) throw new HubException("连接参数错误"); _logger.LogDebug($"用户[{userId}]连接成功,当前客户ID:[{userId}],当前连接ID:[{Context.ConnectionId}]"); clientDic.Add(Context.ConnectionId, userId); await base.OnConnectedAsync(); } public override Task OnDisconnectedAsync(Exception exception) { if (exception != null) _logger.LogError(new EventId(exception.HResult), exception, exception.Message); clientDic.Remove(Context.ConnectionId); return base.OnDisconnectedAsync(exception); } }
1 2 3 4 5 public void ConfigureServices(IServiceCollection services) { services.AddSignalR(option => option.EnableDetailedErrors = true) .AddJsonProtocol(); }
3、在Startup.Configure中配置SignalR路由 1 2 3 4 5 6 7 8 9 app.UseEndpoints(endpoints => { endpoints.MapGet("/", async context => { await context.Response.WriteAsync("Hello World!"); }); endpoints.MapHub<MsgHub>("/msgHub"); });
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 internal class Program { static void Main(string[] args) { try { using (var ws = new WebSocket("ws://localhost:5000/msgHub?uid=567")) { ws.OnOpen += (sender, e) => Console.WriteLine("连接成功。"); ws.OnError += (sender, e) => Console.WriteLine("Error: " + e.Message); ws.OnClose += (sender, e) => Console.WriteLine($"连接关闭, Code:{e.Code};Reason:{e.Reason}"); ws.OnMessage += (sender, e) => { string message = GetSignalrMessage(e.RawData); if (!string.IsNullOrEmpty(message)) { Console.WriteLine("收到消息: " + message); } }; ws.Connect(); ws.Send(AddSeparator(Encoding.UTF8.GetBytes(@"{""protocol"":""json"", ""version"":1}"))); //向服务器发送消息,调用服务器SendMessage方法 SignalrMessage msg = new SignalrMessage { type = 1, target = "SendMessage", arguments = new List<object> { "test send message" } }; string strMsg = JsonConvert.SerializeObject(msg); ws.Send(AddSeparator(Encoding.UTF8.GetBytes(strMsg))); Console.ReadKey(true); } } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.Read(); } /// <summary> /// 添加消息分隔符 /// </summary> /// <param name="data"></param> /// <returns></returns> private static byte[] AddSeparator(byte[] data) { List<byte> t = new List<byte>(data) { 0x1e };//0x1e record separator return t.ToArray(); } /// <summary> /// 移除消息分隔符 /// </summary> /// <param name="data"></param> /// <returns></returns> private static byte[] RemoveSeparator(byte[] data) { List<byte> t = new List<byte>(data); t.Remove(0x1e); return t.ToArray(); } private static string GetSignalrMessage(byte[] data) { string strMessage = Encoding.UTF8.GetString(RemoveSeparator(data)); SignalrMessage message = JsonConvert.DeserializeObject<SignalrMessage>(strMessage); if (message.type.Equals(1) && "ReceiveMessage".Equals(message.target)) { return message.arguments[0].ToString(); } return string.Empty; } } internal class SignalrMessage { public ushort type { get; set; } public string target { get; set; } public List<object> arguments { get; set; } }
运行结果: