.net core 3.0 Signalr - 08 業務實現-客戶端demo


由於signalr作為一個單獨的推送系統,跟業務系統是分離開的,所以此處模擬一個業務系統,新建一個.net core app項目

模擬實現一個登錄功能

我們的登錄很簡單,當進入系統,如果檢測到用戶未登錄則跳轉到登錄頁面,用戶只需要輸入用戶名點擊登錄即算登錄成功

  • 配置ConfigServices方法 查看代碼
    services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, cookieOption =>
    {
        cookieOption.LoginPath = "/Account/Login";
        cookieOption.AccessDeniedPath = "/Account/Login";
    });
    
  • 配置Config方法,配置認證、授權的請求管道 查看代碼
    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
    
  • 接收登錄的post請求,寫cookie,跳轉 查看代碼

前端頁面實現

首先在Layout頁面引入需要的js文件(vue、signalr、msgpack5、signalr-protocol-msgpack) 查看代碼

封裝signalr連接相關js

signalr客戶端js的操作就是,創建連接、監聽推送,封裝后端js如下 查看代碼

/**
 * 初始化連接
 * @param {object} option 參數
 * @param {string} option.url 連接的url地址
 * @param {string} option.loggingLevel 日志級別,默認為 Error
 * @param {number} option.delay 延遲連接 默認為3000毫秒
 * @param {function} option.onStarted 啟動時觸發
 * @param {function} option.onLine 啟動時觸發
 * @param {function} option.offLine 啟動時觸發
 * @returns {object} 連接的實例
 */
function initSignalr(option) {
    var config = Object.assign(true, {
        loggingLevel: signalR.LogLevel.Error,
        delay: 3000,
        url: ''
    }, option);

    var connection = new signalR.HubConnectionBuilder()
        .configureLogging(config.loggingLevel)
        .withUrl(config.url, {
            accessTokenFactory: option.accessTokenFactory
        })
        .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())
        .withAutomaticReconnect([0, 2000, 5000, 10000, 20000])
        .build();

    connection.onreconnecting(function (info) {
        console.info('----------------------------------signalr-- onreconnecting', info);
    });

    connection.onclose(function (err) {
        console.info('--------------------------------signalr-- onclose', err);
    });

    connection.on('OnNotify', config.onNotify);

    connection.on('OnLine', config.onLine);

    connection.on('OffLine', config.offLine);

    setTimeout(function () {
        connection.start().then(function (data) {
            option.onStarted && option.onStarted(data);
        }).catch(function (error) {
            console.error(error.toString());
        });
    }, option.delay);

    return connection;
}

調用封裝的js初始化連接 查看代碼

  • 然后在Home/Index.cshtml中引入上面的js
  • 在頁面加載完后,調用初始化(案例中使用了vue)
    在進入頁面后會彈窗讓用戶輸入加入的組,可以不輸入也可以多個
    function initConnect() {
      $("#collectionUserInfo").modal({
          keyboard: false,
          show: true,
          backdrop: 'static'
      })
    
      $('#collectionUserInfo').on('hidden.bs.modal', function () {
          var groups = $("#groups").val()||'';
          connect=initSignalr({
              delay: 0,
              url:`${notifyUrl}notify-hub?userId=${vm.userInfo.userName}&group=${groups}`,
              loggingLevel: signalR.LogLevel.Error,
              onNotify: dealNotify,
              onLine: function (data) {
                  if (data.IsFirst) {
                      getOnlineUsers();
                  }
                  getOnlineGroups();
                  vm.logs.push(`新連接上線:${JSON.stringify(data)}`);
              },
              offLine: function (data) {
                  if (data.IsLast) {
                      getOnlineUsers();
                  }
                  getOnlineGroups();
                  vm.logs.push(`連接下線:${JSON.stringify(data)}`);
              },
              onStarted: function () {
                  getOnlineUsers();
                  getOnlineGroups();
                  vm.$set(vm.userInfo, 'connectionId', connect.connectionId);
                  vm.$set(vm.userInfo, 'groups', groups);
                  vm.logs.push('連接成功');
              }
          });
      })
      }
    

onNotify方法,如果仔細的話會看到里面的onNotify方法,所有的推送最終都會調用到該方法來進行分發。查看代碼
offLine,當有客戶端下線的時候會觸發,data里面包含有用戶Id、連接Id、是否該用戶的最后一個連接,可根據需要使用查看代碼
onLine,當用戶連接的時候會觸發,data里面包含有用戶Id、連接Id、是否該用戶的第一個連接(用於用戶上線后的邏輯處理),可根據需要使用 查看代碼
onStarted,當成功連接后觸發,可用於做一些連接后的業務邏輯處理,可根據需要使用 查看代碼

獲取當前用戶信息、在線列表

在用戶連接成功后,獲取當前在線用戶、用戶組、當前用戶信息,並設置到vue的data中 查看代碼

模擬一個任務分配

在項目中心中,點擊"模擬推送待辦"按鈕,將會向當前用戶所在組中推送一條代碼消息,可以登錄不同賬號、開多個tab頁體驗
點擊事件代碼位置 查看代碼

assignTaskToUser: function () {
    var that = this;
    $.ajax({
        type: 'POST',
        url: '/api/ServerProxy/AssignTaskToUser',
        data: {
            groups:that.userInfo.groups
        }
    })
},

對應的推送解析代碼

首先當有推送過來的時候,會首先進到onNotify方法,然后根據不同類型在分配到不同的js方法中
查看代碼
效果圖
20190927212304.png

模擬發送消息

消息發送,可以選定組、人進行消息發送
發送端代碼
解析端

登錄互斥

登錄互斥是指,當一個賬號在A電腦登錄,然后再在B電腦登錄,最后的登錄會排斥掉開始的登錄,即,將A上的擠下線
首先用谷歌瀏覽器登錄,輸入用戶名:xiexingen,然后連接
接着使用360急速瀏覽器登錄,輸入用戶名:xiexingen 這個時候會發現谷歌瀏覽器中的登錄已經退出,如圖
20190927213637.png

必要條件: 不同瀏覽器、同一用戶,比如:同一個瀏覽器,不同tab就不算(能共用cookie)

文件下載(指定連接推送)

文件下載的場景,用戶在操作頁面上選擇了上千個文件,然后點擊打包下載,這個時候可能需要很久時間才反應回來,那么這段時間如果讓用戶一直等待顯然不妥,所以,當用戶點擊打包下載的時候,后端啟用一個后台線程去打包、壓縮,然后立即返回;用戶可以繼續操作,當服務器端打包好后推送給用戶端,用戶點擊下載即可。
此處分兩種情況

  1. 單連接推送
    用戶開了多個tab頁,在其中一個上下載文件,如果后端推送的時候,直接給該用戶推,顯然不妥;正確的做法一個是只給操作的那個tab頁推,這就需要,調用服務器端業務api的時候,需要把當前tab頁對應的連接id發送到服務器端,服務器端處理完業務后,調用推送服務器,告訴推送服務器只推我給你的這個連接的客戶端,這樣就能指定連接推送。
  2. 單用戶排除某個連接的其他連接推送
    這種情況比較少見,告訴推送服務器,給這個用戶,除了某個連接外的其他所有連接推送

模擬操作
點擊第一個圖中的"打包下載文件" 按鈕,當前頁面會受到文件下載的推送
在點擊圖二中的"推送當前用戶其他頁面更新操作"按鈕,會發現出了當前tab頁外,其他tab也都收到了推送消息,如下圖
20190927214530.png

至此,signalr相關文章算是到此結束了,下一篇談談個人的一點心得以及里面存着的一些問題。

快速導航

標題 內容
索引 .net core 3.0 Signalr - 實現一個業務推送系統
上一篇 .net core 3.0 Signalr - 07 業務實現-服務端 自定義管理組、用戶、連接
下一篇 .net core 3.0 Signalr - 09 待改進&交流
源碼地址 源碼
官方文檔 官方文檔

二維碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM