SignalR在ASP.NET CORE下的使用
SignalR是微软提供的实时Web通信的库,
它会自己根据情况使用不同的链接方式,主要有
- WebSocket
- long polling
- Forever frame
- Sever Events Sent
等方式,故可以不管其具体的实现方式,差不多等于开箱即用了。
一.StartUp中的起始配置
在StartUp中添加配置
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddSignalR(); //只需要添加AddSignalR
services.AddControllers();
services.AddCors(options =>
options.AddPolicy("lingluAllCors",
p => p.AllowAnyOrigin().
AllowAnyHeader().
AllowAnyMethod()));
#endregion
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapRazorPages();
//添加/注册对应的Hub类,并添加路由
//请注意:在不同的.Net Core版本中,MapHub方法也可能在app中
//如果找不到MapHub请两个地方都试一试
endpoints.MapHub<ChatHub>("/chatHub");
});
app.UseCors("lingluAllCors");
}
二.配置Hub中心类和服务器推送信息
Hub类是SignalR的核心工具类
它主要有两个功能
1. 向Client(浏览器)的监听处主动推送消息【服务器主动推送数据】
2.接受Client的发起的信息(请求),【普通的请求----->响应模式】
例:Hub类的简单解释
public class ChatHub : Hub
{
//继承Hub类可以复写
//Task OnDisconnectedAsync(Exception exception)
//Task OnConnectedAsync()
//以上方法在Client链接/断开时被触发,而推送/接受信息的方法则需要你自定义
//Hub里的方法不在后台调用,而是通过函数名和参数在前端进行js调用
public async Task SendMessage(string user, string message)
{
//这里和普通的 请求---->响应 的方式很像
//在这里拿到参数,写一些逻辑
Console.WriteLine("User is" + user + " | Message is"+message);
//但区别在于,你可以选择是否响应
//这个SendAsync在下一小节细讲
//Clients.All.SendAsync("ReceiveMessage2", user, message);
}
//如果请求需要返回,也可以多次返回(或是一些有条件的返回)
public async Task SendMessage2(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage2", user, message);
for (int i = 0; i < 10; i++)
{
Thread.Sleep(2000);
await Clients.All.SendAsync("ReceiveMessage2","van you see","luckshit");
}
}
}
例:服务器主动推送消息给前端
当你完成自定义Hub类,并把它注册到StartUp中,
你就能通过ASP.NET CORE自带的DI(依赖注入)
获取该类型(你自定义的Hub)泛型的IHubContext对象,
然后后台就可以在链接存在时随时的推送数据了
以一个Controller为例:
[Route("api/[controller]/[action]")]
[ApiController]
public class SendController : ControllerBase
{
//可以通过DI来获取指定的自定义中心泛型的IHubContext工具
private readonly IHubContext<ChatHub> _hubContext;
public SendController(IHubContext<ChatHub> hubContext)
{
_hubContext = hubContext;
}
[HttpGet]
public async Task<string> SendData(string message)
{
//给前端监听的ReceiveMessage2方法传递参数
await _hubContext.Clients.All.SendAsync("ReceiveMessage2", "van you see", "luckshit");
return "something you want";
}
}
三.前端代码和显示
前端的显示
需要微软提供的js文件
如果你使用node.js的话,可以在直接npm install下来,不使用的话也可以直接引入js文件
npm install @microsoft/signalr
# or
yarn add @microsoft/signalr
链接:
@microsoft/signalr - npm (npmjs.com)
在项目中创建页面,然后引入js
页面代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<div class="container">
<div class="row"> </div>
<div class="row">
<div class="col-2">User</div>
<div class="col-4"><input type="text" id="userInput" /></div>
</div>
<div class="row">
<div class="col-2">Message</div>
<div class="col-4"><input type="text" id="messageInput" /></div>
</div>
<div class="row"> </div>
<div class="row">
<div class="col-6">
<input type="button" id="sendButton" value="Send Message" />
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<hr />
</div>
</div>
<div class="row">
<div class="col-6">
<ul id="messagesList"></ul>
</div>
</div>
<!--引入js文件-->
<script src="./lib/microsoft/signalr/dist/browser/signalr.js"></script>
<script>
//初始化客户端 官网 https://docs.microsoft.com/zh-cn/aspnet/core/signalr/javascript-client?view=aspnetcore-5.0&tabs=visual-studio
//创建链接并指定到在StartUp中配置的Chathub的路由,
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.configureLogging(signalR.LogLevel.Information)
.build();
//start开始连接,
async function start() {
try {
//会在后台触发连接Hub的Task OnConnectedAsync()方法,
await connection.start();
//如果想要在链接处获取身份信息,即使用/获取自带的UserID/Group对象什么的,
//需要使用ASP.NET CORE 官方的authorize, 和Identity的相关内容,如果使用的是自研的登陆和认证内容,则无法使用以上的user对象
//请手动发送empno/username等信息
console.log("SignalR Connected.");
console.log(connection.connectionId);
} catch (err) {
console.log(err);
//异步发起重连
setTimeout(start, 5000);
}
};
//重连机制
connection.onclose(async () => {
await start();
});
//ReceiveMessage2为监听的数据标识,可自定义
//解释:当后台调用hub对象(IHubContext)SendAsync时,指定的第一个参数即为此标识时(或者直说第一个method参数等于此标识时),则前端会自动调用对应的函数,
// 后台的返回值则会注入到前端的参数中
connection.on("ReceiveMessage2", function (user, message) {
//UI显示监听的数据
var li = document.createElement("li");
document.getElementById("messagesList").appendChild(li);
li.textContent = `ReceiveMessage2:${user} says ${message}`;
});
//发起连接
start();
//按钮事件(发送链接)
document.getElementById("sendButton").addEventListener("click", function (event) {
var user = document.getElementById("userInput").value;
var message = document.getElementById("messageInput").value;
SendMessage2为自定义方法ChatHub.cs 定义的相同
connection.invoke("SendMessage2", user, message).catch(function (err) {
return console.error(err.toString());
});
event.preventDefault();
});
</script>
</body>
</html>
四.运行和测试
后台推送信息给前台
运行程序,开打页面和开发者工具
然后,调用Controller中的测试方法 api/Send/SendData
调用Hub对象(IHubContext)的SendAsync方法
然后再回到前端查看页面的效果
常规的前端请求到后台(在Signalr中可以不作响应)
在页面的输入框中输入数据,提交去触发前端 hubconnection的invoke方法,
后台调用invoke指定的Hub类的方法
(定义的Hub类中的对应方法,注意:这里的Hub类不是Hub对象(IHubContext))
然后在方法体中给前端的监听函数推送信息。
这种方式就和请求响应的模式很接近,但是也可以不响应(情况比较少)。
测试小节总结
一定要弄清Hub类的作用,
- Hub类中定义的方法为只能被前端invoke调用,但是否响应(SendAsync)是可选的
- 当你在其他的地方要推送信息(SendAsync)时,使用的是IHubContext
- IHubContext可以使用DI,你可以在后台的任何地方自动发送消息
- 不要尝试将IHubContext 转化为T,后台无法调用Hub类方法,路已被锁死
补充
Hub可以获取指定Client,
并有一套API和ASP.NET CORE 的Autherize,Identity配合可以
获取User,Group,Auth…的信息,
如果你的程序没有用到ASP.NET CORE的Authrize,那就用不了。
但是可以在连接开始阶段发送用户信息,然后借以统计是否存在链接/对手链接
https://download.csdn.net/download/jamenu/87380909?spm=1001.2014.3001.5501
不要尝试将IHubContext 转化为T,后台无法调用Hub类方法,路已被锁死