在原生js实现文件上传并显示进度条一文中,咱们实现了一个Excel上传功能,而且显示了服务端实时处理进度(正在处理第N行...)
,不用让用户一直傻等而不知道什么状况,这样极大的提升了用户的体验前端
有两种方式能够实现这样的功能:node
js
去定时请求服务端处理进度/长轮询websocket
双向通讯两种方案的选择:web
传统的长轮询也能实现消息实时,就是定时向服务器发送请求获取消息,可是这样对服务器压力比较大,而websocket
基于http
进行一次握手功能,后面就不走http
了chrome
在.net
中,SignalR
用来实现服务器和客户端双向通讯的一个框架,是对websocket
的很好的一个封装,因此我选择了它。浏览器
固然,其余语言确定都是支持websocket
通讯的,不单单局限于.net
,像nodejs
的socket.io
bash
SignalR
是.net
中的一个服务器和客户端双向通讯的一个框架,面向web端的即时通信,SignalR
更简单,对websocket
通讯进行了封装服务器
SignalR
没有链接限制,取决于服务器配置,浏览器客户端有限制,chrome通常是5个websocket
链接websocket
websocket
,就使用websocket
通讯协议,不然就降级,使用长轮询 服务器通常须要手动开启
.net core
跨平台,在2.2版本已经正式内置了SignalR
.net core
服务端配置startup
中ConfigureServices
方法内部添加SignalR
服务services.AddSignalR();
,Configure
中配置具体的Hub
(路由器、中转):app
app.UseSignalR(routes =>
{
routes.MapHub<TestHub>("/testHub"); //能够多个map
});
app.UseMvc(); //注意UseSignalR须要在UseMvc()以前
复制代码
这样SignalR
服务器端就开发完成了,网页、Java、.Net客户端均可以链接的框架
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();
}
复制代码
开了两个浏览器访问,基本的效果如图:
到这里,咱们彻底能够作一个聊天室了,固然,须要优化的地方会更多了
在构造函数注入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){
//根据返回的参数进行相应的逻辑处理展现...
})
复制代码
到这里,SignalR
的基本用法已经介绍完毕,欢迎补充!