SignalR

Posted 生命不息bug不止

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SignalR相关的知识,希望对你有一定的参考价值。

SignalR是一个可以让服务器向客户端实时推送消息的库

上图是他基本原理,多个客户端连接同一个服务器,当客户端A调用服务器的方法时,服务器会调用所有客户端的方法,这样客户端B和客户端C,虽然没做操作,但是依然会收到消息

例如QQ群聊天,一个人发出一条消息,其他人都会收到这条消息

 

首先要添加一个名为Startup的类(并不知道这个类是干嘛的,但我猜是注册) 

 public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }

然后我们开始写服务端

服务端的类必须要继承Hub类

public class SigHub:Hub
    {
        
    }

然后在这个类中写一些方法,供客户端调用

public class SigHub:Hub
    {
        public void ServerShow(string text)
        {
            Clients.All.clientShow(text);
        }
    }

方法内的操作是调用所有客户端的clientShow方法(虽然我们客户端还没写,这个方法自然也还没有,但是不要紧,后面记得写上就行)

到这里我们就能大致明白上面说的基本原理和图了

一个客户端调用服务端的ServerShow方法,然后ServerShow调用所有客户端的clientShow方法

 

接下来我们去写客户端

客户端是网页,写在js中

首先引用三个必要的js文件

<script src="Scripts/jquery-1.6.4.js"></script>
<script src="Scripts/jquery.signalR-2.2.2.js"></script>
<script src="/signalr/hubs"></script>

第三个文件是生成的,项目里看不到,总之写上就行了

第一步 帮你的服务端类存到变量里

注 sigHub是你服务端里写方法的类名

        var hub = $.connection.sigHub;

然后把服务端调用的客户端方法创建出来

hub.client.clientShow = function (date) {
            alert(date);
}

最后调用服务端的方法

$.connection.hub.start().done(function () {
            hub.server.serverShow("12313");
});

完整代码

<script>
        var hub = $.connection.sigHub;
        hub.client.clientShow = function (date) {
            alert(date);
        }
        $.connection.hub.start().done(function () {
            hub.server.serverShow("12313");
        });
</script>

 

SignalR有几种不同的推送方式

Clients.Caller 推送给当前用户(大概)

Clients.All 推送给所有用户

Clients.Others 推送给自己以外所有的用户

Clients.Client(connectionid) 推送给指定的用户

Clients.Group(GroupId) 推送给指定组中的用户

 

Core版本的使用

引用core版本类库

Install-Package Microsoft.AspNetCore.SignalR -Version 1.0.0-alpha2-final (还没有正式版)

建立一个hub类,和framework的一样要继承于Hub

然后对Startup进行配置

在ConfigureServices中加上 services.AddSignalR();

public void ConfigureServices(IServiceCollection services)
        {
           
            services.AddSignalR();

            //↓用来跨域的不用在意
            services.AddCors(options =>
            {
                options.AddPolicy("any", builder =>
                {
                    builder.AllowAnyOrigin() //允许任何来源的主机访问
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials();//指定处理cookie
                });
            });
            services.AddMvc(); //← 本来就有的不用在意
        }            

之后在Configure中注册我们的hub类

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            //↓本来就有
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            //↓加上才能访问wwwroot中的静态文件
            app.UseFileServer();
            //↓跨域
            app.UseCors("any");

            //↓注册hub
            app.UseSignalR(routes =>
            {
                routes.MapHub<SigHub>("sigHub");
            });

            //↓路由设置为MVC那样
            app.UseMvcWithDefaultRoute();
            //↓本来就有
            app.UseMvc();
        }                

这样我们的SignalR就配置好了,接下来就是如何使用

首先是我们的hub类,变化并不是很大,但还是有不同的地方

 

public void Test(string msg) 
{
       Clients.All.test(msg); //←framework的写法
       
       Clients.All.InvokeAsync("test",msg); //←core的写法
}    

我把两个的写法放到一起给你们对比一下,这样更清楚变化

framework版本是直接在后面点客户端的方法名来调用,参数也是直接放在方法的括号中就行了

core版本的点后面则是一个固定的方法InvokeAsync

方法的第一个参数是客户端的方法名,第二个参数是要传的参数

如果不止一个参数的话,直接在后面继续写就行了

Clients.All.InvokeAsync("test","参数1","参数2","参数3");

对客户端的几种不同调用方式

All 全部调用

Client 调用指定的客户端

Group 调用指定组当中的客户端

(other不知为什么没有了)

以上就是服务端的写法,接下来讲解客户端的写法

客户端的变化就比较大了

它需要引用一个名为signalr-client-1.0.0-alpha2-final的js文件

首先要创建一个连接对象

var transport = signalR.TransportType.LongPolling; //连接类型
var connection = new signalR.HubConnection(`http://localhost:65449/sigHub`, { transport: transport }); //创建连接对象
connection.start();//打开连接

之后是注册服务端调用的客户端方法

connection.on("test", function (msg) {
         $("ul").append("<li>" + msg + "</li>");
});

function中的msg就是从服务端传过来的参数

最后是调用服务端的方法

$("#send").click(function () {
                var date = "abc";
                connection.invoke("test",date); //调用服务端的Test方法
});

注意:即使在服务端写的方法名是开头大写的,客户端调用时也要小写

date则是传给服务端的参数,不需要传参的话就不用写

connection.invoke("test");

 

页面的代码

<button id="send">发送</button>
<ul>

</ul>

 

完整的代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
    <script src="jquery.js"></script>
    <script src="signalr-client-1.0.0-alpha2-final.js"></script>
    <script>
        $(function () {
            var transport = signalR.TransportType.LongPolling; //连接类型
            var connection = new signalR.HubConnection(`http://localhost:65449/sigHub`, { transport: transport }); //创建连接对象
            connection.start(); //打开连接
            
            //注册客户端方法
            connection.on("test", function (msg) {
                $("ul").append("<li>" + msg + "</li>");
            });
            //调用服务端方法
            $("#send").click(function () {
                var date = "abc";
                connection.invoke("test",date);
            });
        })
        
    </script>
</head>
<body>
    <button id="send">发送</button>
    <ul>

    </ul>
</body>
</html>

 

效果

 

这就是SignalR的Core版本使用了,最后说下跨域

SignalR的hub类可以被跨域访问,只要普通的配置一下core的api跨域就行了,这里就不说了 (其实在上面的配置中已经把跨域配置也写出来了)

以上是关于SignalR的主要内容,如果未能解决你的问题,请参考以下文章

SignalR OnConnected 与多台服务器和 Redis 背板

C# SignalR:从代码隐藏更新数据的问题

角度 SignalR 经常断开连接并显示错误状态代码 1006

websocket握手代码期间无法连接signalR错误:400

ASP.NET Core SignalR :SignalR Javascript 客户端

SignalR - 从服务器端代码调用 Hub 类方法(存在于单独的 MVC 项目中)