.net core SignalR——服務器實時消息推送

背景

原生js實現文件上傳並顯示進度條一文中,咱們實現了一個Excel上傳功能,而且顯示了服務端實時處理進度(正在處理第N行...),不用讓用戶一直傻等而不知道什麼狀況,這樣極大的提升了用戶的體驗前端

有兩種方式能夠實現這樣的功能:node

  1. 前端js去定時請求服務端處理進度/長輪詢
  2. websocket雙向通訊

兩種方案的選擇:web

傳統的長輪詢也能實現消息實時,就是定時向服務器發送請求獲取消息,可是這樣對服務器壓力比較大,而websocket基於http進行一次握手功能,後面就不走httpchrome

.net中,SignalR用來實現服務器和客戶端雙向通訊的一個框架,是對websocket的很好的一個封裝,因此我選擇了它。瀏覽器

固然,其餘語言確定都是支持websocket通訊的,不單單侷限於.net,像nodejssocket.iobash

SignalR

SignalR.net中的一個服務器和客戶端雙向通訊的一個框架,面向web端的即時通信,SignalR更簡單,對websocket通訊進行了封裝服務器

SignalR沒有鏈接限制,取決於服務器配置,瀏覽器客戶端有限制,chrome通常是5個websocket鏈接websocket

能夠作什麼

  • 站內實時聊天、消息通知
  • web頁面實時數據的展現
  • 自適應通訊協議,若是瀏覽器或服務器支持websocket,就使用websocket通訊協議,不然就降級,使用長輪詢 服務器通常須要手動開啓
  • .net core跨平臺,在2.2版本已經正式內置了SignalR

.net core服務端配置

startupConfigureServices方法內部添加SignalR服務services.AddSignalR();Configure中配置具體的Hub(路由器、中轉):app

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端引入SignalRjs對應類庫,調用服務端對應的方法便可

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){
    //根據返回的參數進行相應的邏輯處理展現...
})
複製代碼

到這裏,SignalR的基本用法已經介紹完畢,歡迎補充!

相關文章
相關標籤/搜索