asp.net core版本:5.0
Vue版本:2.5.2
本文是入门教程,主要讲解如何利用SignalR从客户端调用服务器的函数,以及从服务器调用客户端的函数。
首先看一下服务端代码:
添加SignalR服务:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSignalR();
services.AddCors(opt =>
{
opt.AddPolicy("SignalRCorsPolicy", corsBuilder =>
{
corsBuilder.AllowAnyHeader().WithOrigins("http://localhost:8080").AllowCredentials();
});
});
}
SignalR服务是asp.net core自带的,所以不需要从Nuget包管理器中添加。
因为客户端和服务器是跨域的,所以需要配置跨域。withOrigins的参数就是服务器允许访问的客户端地址,我这里的地址就是vue客户端的运行地址。如果我们不设置Origins(也就是任何客户端都可以访问该服务器),把WithOrigins改成AllowAnyOrigin(),那服务器就会报这样的错:
这个意思就是跨域协议不能同时允许所有源和证书访问。而且为了服务器的安全,我们也不建议这样的设置。 然后在配置管道时,加上app.UseCors("SignalRCorsPolicy");注意这行代码必须放在UseRouting
和UseAuthorization
之间,因为中间件的调用是有顺序的。
最后我们需要配置一下集线器的路径;
app.UseEndpoints(endpoints =>
{
endpoints.MapHub("/counthub");
endpoints.MapControllers();
});
接下来我们创建一个集线器类,让这个类继承自Hub,Hub的命名空间是:Microsoft.AspNetCore.SignalR
下面我们来看一下Vue客户端的代码(客户端我使用的是Vue的单页面应用,由template、script、style这3个模块组成)
首先我们需要安装SignalR包:npm install @aspnet/signalr。我在有些博客上看到的包名是:@microsoft/signalr,我最开始安装的是这个包,但是安装完之后这个包编译报错,所以我安装的是@aspnet/signalr包。
引入signalr:const signalR = require('@aspnet/signalr')
定义一个全局的connection变量,因为我们需要在不同的函数中使用这个变量,所以把它定义成全局的:
data () {
return {
connection: ''
}
},
在页面加载后连接SignalR服务器
created () {
this.initSignalR()
},
在methods里面定义initSignalR函数:
initSignalR () {
this.connection = new signalR.HubConnectionBuilder()
.withUrl('http://localhost:5000/counthub', {}).build()
this.connection.on('ConnectSucceeded', data => {
console.log(data)
})
this.connection.start()
}
on函数就是提供给服务器调用的客户端函数,函数名是ConnectSucceeded,data是服务器返回给客户端的数据,可以是基础类型也可以是对象。
在服务器端的集线器抽象类Hub中,有一个虚函数OnConnectedAsync,就是建立连接后调用的函数,我们重写一下这个函数,给连接服务器的客户端发送一个连接成功的消息
public override Task OnConnectedAsync()
{
Clients.Caller.SendAsync("ConnectSucceeded", "恭喜您,SignalR建立连接成功了");
return base.OnConnectedAsync();
}
Clients.Caller这个表示建立这个连接的客户端,这条信息只发送给建立这个连接的客户端。
SendAsync的第一个参数是客户端的函数名,第二个参数是发送给客户端的数据
接下来我们就可以运行服务器和客户端来建立连接了。在打开vue页面的时候,vue就会发起连接请求。按F12,打开浏览器的控制台,输出如下:
现在连接已经建立成功了,下面我们从客户端调用服务器的函数并从服务器调用客户端函数
在template添加一个按钮,给按钮添加一个点击事件:
sendRequest () {
this.connection.invoke('Play', '霍去病').catch(function (err) {
console.error(err)
})
}
在客户端定义一个play函数,给服务器调用:
this.connection.on('play', data => {
console.log(data)
})
服务端集线器类代码:
public async Task Play(string name)
{
await Clients.All.SendAsync("play", $"server return :{name}");
}
客户端控制台输出如下: