前言
Asp.Net SignalR 已经出来很久了, 但是一直没有静下心来好好看看. 昨天花了几个小时的时间看了下. 首先借鉴了官方文档, 如何搭建一个 SignalR 的 Demo.
参考文章:
SignalR 地址: https://github.com/aspnet/SignalR
所以为了快速搭建和体验. Net Core 版本的 SignalR, 我选择了下载官方的 Demo 和参考官方给的教程. 所以具体的搭建过程我就不再本文中写了.
体验效果
官网给出的 DEMO 运行如下图:
点击 connect, 查看一下 network. 可以发现, 它在当前浏览器支持三种方式.
而且和. NET Framework 版本不同的是, 新版 SignalR 中的 Hub 类型也是蛮丰富的. Demo 中给出了 普通 Hub,DynamicHub,Hub<T> 三种类型. 我们去看看其中的区别吧.
普通 Hub
查看定义, 可以看到普通 Hub 中的 Clients 类型是 IHubCallerClients
- namespace Microsoft.AspNetCore.SignalR
- {
- //
- // 摘要:
- // A base class for a SignalR hub.
- public abstract class Hub : IDisposable
- {
- protected Hub();
- //
- // 摘要:
- // Gets or sets an object that can be used to invoke methods on the clients connected
- // to this hub.
- public IHubCallerClients Clients { get; set; }
- //
- // 摘要:
- // Gets or sets the hub caller context.
- public HubCallerContext Context { get; set; }
- //
- // 摘要:
- // Gets or sets the group manager.
- public IGroupManager Groups { get; set; }
- //
- public void Dispose();
- //
- // 摘要:
- // Called when a new connection is established with the hub.
- //
- // 返回结果:
- // A System.Threading.Tasks.Task that represents the asynchronous connect.
- public virtual Task OnConnectedAsync();
- //
- // 摘要:
- // Called when a connection with the hub is terminated.
- //
- // 返回结果:
- // A System.Threading.Tasks.Task that represents the asynchronous disconnect.
- public virtual Task OnDisconnectedAsync(Exception exception);
- //
- // 摘要:
- // Releases all resources currently used by this Microsoft.AspNetCore.SignalR.Hub
- // instance.
- //
- // 参数:
- // disposing:
- // true if this method is being invoked by the Microsoft.AspNetCore.SignalR.Hub.Dispose
- // method, otherwise false.
- protected virtual void Dispose(bool disposing);
- }
- }
IHubCallerClients 定义如下:
- public interface IHubCallerClients : IHubCallerClients<IClientProxy>, IHubClients<IClientProxy>
- {
- }
而框架又给 IClientProxy 增加了扩展方法: SendAsync
所以在普通 Hub 中, 定义客户端方法的时候, 需要把方法名当作参数传入 SendAsync 方法中. 例如如下代码:
- public Task Send(string message)
- {
- return Clients.All.SendAsync("Receive", $"{Context.ConnectionId}: {message}");
- }
- DynamicHub
DynamicHub 我是比较喜欢的, 因为他和 Framework 版的是一样 (或者说看起来是一样的) 的. 动态 Hub 我们就可以不必拘泥于只能调用 SendAsync 方法了. 例如:
- public Task SendToOthers(string message)
- {
- return Clients.Others.ThisIsMyReceiveMethod($"{Context.ConnectionId}: {message}");
- }
DynamicHub 的 Clients 类型为: DynamicHubClients , 它的内部变量全都是 dynamic 类型的.
Hub<T>
泛型 Hub 就把规约交给开发者制定. 在 Demo 中 Hub<IChatClient> 中的 IChatClient 接口定义了 Receive 方法, 因此 Clients 中的对象可以调用 Receive 方法. 同理, 我们可以根据业务需要定义自己的方法. 至少从代码上看会显得更加通俗易懂一些. 比如:
- public interface IChatClient
- {
- Task Receive(string message);
- Task LoginSuccess(long userId);
- }
- public Task Login(long userId)
- {
- return Clients.Caller.LoginSuccess(userId);
- }
其实从代码上来看的话, 他们都是 Hub, 只不过是不同的扩展实现而已. 而泛型 Hub 不过是用户自定义泛型接口, 而默认 Hub 中的默认泛型接口为: IClientProxy. 所以看到这里, 如果我就想使用原生的 Hub 而又想自定义方法怎么办呢? 很简单, 加扩展就可以了.
为什么自己加就可以呢, 其实 SendAsync 就是扩展方法, 它内部也是调用了 SendCoreAsync 方法. 于是乎, 写下自己的扩展方法, 那这样子就很灵活了. 我们把 method 参数去掉, 直接写死试试:
- public static Task LoginAsync(this IClientProxy clientProxy, string message, CancellationToken cancellationToken = default(CancellationToken))
- {
- return clientProxy.SendCoreAsync("LoginSuccess", new object[] { message}, cancellationToken);
- }
其实说白了, 这个扩展方法还是需要传入 method 参数的, 只不过封装了一层(似乎感觉这么做有意义吗? 哈哈, 还是老老实实用泛型吧), 那么我们在去看 Hub 中的方法, 修改 Send 方法如下:
- public Task Send(string message)
- {
- return Clients.All.LoginAsync($"{Context.ConnectionId}: {message}");
- }
是不是这样子就实现了自己自定义方法了呢? 个人觉得这么写还绕了一圈, 不如用泛型或者 Dynamic 了.
运行一下, 看看效果:
其实我也是抱着试试的态度, 没想到还真是这样, 和新方法就是 SendCoreAsync, 而其他方法只不过是上层封装使得代码更加通俗易懂.
使用 Redis
Demo 中的其他例子就不再演示了. 广播, 一对一, 一对多, 加入组, 退出组等基本和之前一样. 这里在演示一下使用 Redis 做不同实例之间的通信效果.
首先程序集是不能少的: Microsoft.AspNetCore.SignalR.Redis, 然后在 Startup 中补充代码:
打开 Redis 客户端, 使用 MONITOR 命令监听一下, 从程序启动, 到连接, 在发送一条广播消息: hello redis. redis 监听结果如下:
所以, PUB/SUB 还是立了大功呢.
这里用 CMD 运行了两个实例, 端口分别为 8881,8882 来模拟两个站点.
演示效果如下:
没问题的哦, 其实仔细想想, 虽然运行了两个网站实例, 但是连接信息都保存在同一个 Redis 上, 那肯定通信是木的问题的啦.
总结
只是简单的运行了一下 DEMO, 大致了解了一下 .Net Core SignalR 的表层, 至少跑 Demo 是跑起来了, 并且使用 Redis 也是没有问题的. 不过好像会出现运行一旦时间, 程序自动停掉的问题, 不知道是不是我电脑的问题.. 今天就到这里吧, 希望大家能有所收获. 本文代码地址:
来源: https://www.cnblogs.com/panzi/p/9649315.html