查看原文
其他

.NET Core SignalR 初体验

DotNet 2019-08-03

(点击上方蓝字,可快速关注我们)


来源:丶Pz

cnblogs.com/panzi/p/9649315.html


前言


ASP.NET SignalR已经出来很久了,但是一直没有静下心来好好看看。


花了几个小时的时间看了下。


首先借鉴了官方文档,如何搭建一个SignalR的Demo。


参考文章:https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/signalr?view=aspnetcore-2.1&tabs=visual-studio 


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://github.com/fanpan26/LayIM.AspNetCore/tree/master/src/LayIM.AspNetCore.Demo/SignalRSamples


看完本文有收获?请转发分享给更多人

关注「DotNet」,提升.Net技能 

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存