在原生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
的基本用法已經介紹完畢,歡迎補充!