SignalR
SignalR是.net中的一个服务器和客户端双向通信的一个框架,面向web端的即时通讯,SignalR更简单,对websocket通信进行了封装
SignalR没有连接限制,取决于服务器配置,浏览器客户端有限制,chrome一般是5个websocket连接
可以做什么
- 站内实时聊天、消息通知
- web页面实时数据的展示
- 自适应通信协议,如果浏览器或服务器支持websocket,就使用websocket通信协议,否则就降级,使用长轮询 服务器一般需要手动开启
- .net core跨平台,在2.2版本已经正式内置了SignalR .net core服务端配置
startup中ConfigureServices方法内部添加SignalR服务services.AddSignalR();,Configure中配置具体的Hub(路由器、中转):
app.UseSignalR(routes =>
{
routes.MapHub<TestHub>("/testHub"); //可以多个map
});
app.UseMvc(); //注意UseSignalR需要在UseMvc()之前
这样SignalR服务器端就开发完成了,网页、Java、.Net客户端都可以连接的
Hub 消息处理中心
public class TestHub : Hub
{
public TestHub()
{
}
public async Task SendMessage(string message, string name)
{
#region Client
//this.Context.ConnectionId //每个连接一个connectionId 表示唯一客户端
//this.Clients.Client().SendAsync(); //指定发送消息
//this.Clients.Clients()
#endregion //给多个client发消息
#region Group
//this.Clients.Group(); //给某个组发消息
//this.Clients.Groups() //给多个组发消息
//this.Groups.AddToGroupAsync() //将指定连接加入组
//this.Groups.RemoveFromGroupAsync() //将指定连接移除组
#endregion
await Clients.All.SendAsync("onMsg", DateTime.Now, message);
}
//上下线消息 连接、断开事件
//客户端连接上
public override Task OnConnectedAsync()
{
return base.OnConnectedAsync();
}
//客户端断开
public override Task OnDisconnectedAsync(Exception exception)
{
string connectionId = this.Context.ConnectionId;
return base.OnDisconnectedAsync(exception);
}
}
以上可以看到SignalR封装了很多常用方法(发送指定消息、群发…),我们可以很简单的使用达到目的
web端引入SignalR的js对应类库,调用服务端对应的方法即可
var connection = new signalR.HubConnectionBuilder().withUrl("/testHub").build();
connection.on("onMsg", function (data, message) {
console.log(data);
var li = document.createElement('li');
li.textContent = `${data}:${message}`;
document.getElementById("content").appendChild(li);
});
connection.start().then(function () {
}).catch(function (err) {
})
function sendMsg() {
var msg = document.getElementById('txt').value;
connection.invoke("SendMessage", msg, "xiaoqiu");
//connection.stop();
}
```
开了两个浏览器访问,基本的效果如图:

到这里,我们完全可以做一个聊天室了,当然,需要优化的地方会更多了
Controller中调用SignalR服务
在构造函数注入IHubContext<>就可以直接使用了,非常方便:
private readonly IHubContext<TestHub> _hubContext;
public HomeController(IHubContext<TestHub> hubContext)
{
_hubContext = hubContext;
}
public async Task<IActionResult> Notify()
{
//拿不到当前Hub的clientId 线程是唯一的
await _hubContext.Clients.All.SendAsync("onMsg", "from controller msg");
return Ok();
}
一般不直接和客户端进行Hub通信,Controller中调用Hub可以做中转,做多应用接入,自定义功能、权限等等
上一文中,我们显示Excel试试处理进度,大致代码如下:
[HttpPost]
public async Task<JsonResult> Import()
{
var connectionId = Request.Form["connectionId"].ToString(); //拿到当前连接的Id
var importer = new ExcelImporter();
//自定义的委托,处理业务的参数
importer.OnImportingEvent += (sender, arg) =>
{
var response = new
{
isSuccess = arg.IsSuccess, //当前数据行是否处理(导入转换)成功
total = arg.TotalRow, //当前导入的数据总行数
rowNumber = arg.RowNumber, //当前处理的行数
msg = arg.Msg, //处理消息
time = arg.Time, //处理时间
isComplete = false //是否全部处理(转换)完毕
};
//推送消息,通知到客户端
_globalHub.InvokeByIDAsync(connectionId, "importMessage", response);
};
}
//前端的connection处理,监听对应的方法
connection.on('importMessage',function(notice){
//根据返回的参数进行相应的逻辑处理展示...
})