1. 程式人生 > >史上最全面的SignalR系列教程-3、SignalR 實現推送功能-集線器類實現方式

史上最全面的SignalR系列教程-3、SignalR 實現推送功能-集線器類實現方式

1、概述

通過前兩篇

史上最全面的SignalR系列教程-1、認識SignalR

史上最全面的SignalR系列教程-2、SignalR 實現推送功能-永久連線類實現方式

文章對SignalR的介紹,我們對SignalR已經有了全面的認識。SignalR API 客戶端和伺服器端持久連線的通訊方式,一次連線代表一個傳送單個、分組或者廣播訊息的簡單終端。持久連線的API(表現在.NET的PersistentConnection 類上)給了開發人員低價訪問SignalR所暴露的通訊協議的條件。使用這種連線方式,就像開發人員使用WCF一樣。

本篇將繼續在上一篇的基礎上,講解SignalR通過最常用的集線器方式實現訊息推送與傳送。

我們知道SignalR的通訊模型主要是兩類Persistent Connections與Hubs。Hub是一種更高階的管道,它在連線協議上允許客戶端和伺服器端能夠直接呼叫彼此的方法。SignalR的這種自動分發跨機器邊界排程的方法就像施了魔法一樣,讓客戶端呼叫服務端的方法像呼叫本地一樣簡單,反之亦然。使用Hub的模式就像開發人員使用遠端API一樣,比如 .NET Remoting。使用Hub同樣能夠讓你傳遞型別化的引數到方法上進行模型繫結。通過Hubs實現服務端訊息推送到客戶端,抽象結構圖如下。

2、SignalR Hub 原理分析

SignalR具體是如何到達實行性的呢?SignalR 的實現機制與 .NET WCF 或 Remoting 是相似的,都是使用遠端代理來實現。SignalR 將整個連線,資訊交換過程封裝得非常漂亮,客戶端與伺服器端全部使用 JSON 來交換資料。

當服務端的程式碼訪問一個客戶端的方法時,一個數據包被自動傳輸,資料包中包含了函式方法引數的名稱(如果是一個物件,那麼這個物件會被序列化成JSON)。客戶端然後根據客戶端的程式碼匹配方法的名稱。如果找到相應的匹配方法,那麼久呼叫相應的函式執行反序列化的引數。

3、Hubs實現實時訊息流程

  • 在伺服器端定義對應的hub class;

  • 在客戶端定義hub class 所對應的 proxy 類;

  • 在客戶端與伺服器端建立連線(connection);

  • 然後客戶端就可以呼叫 proxy 物件的方法來呼叫伺服器端的方法,也就是傳送 request 給伺服器端;

  • 伺服器端接收到 request 之後,可以針對某個/組客戶端或所有客戶端(廣播)傳送訊息。

4、SignalR的Hub連線類Mvc實現

我們繼續在上一篇專案基礎上擴充套件hubs的方式的使用。具體新增專案、新增signalr引用等可以參考上一篇。

4.1、向工程中新增HubConnections目錄,在其中新增ChatHub.cs檔案,如下圖所示:

程式碼內容如下:

using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;

namespace SignalRTestProj.HubConnections
{
    //HubName 這個特性是為了讓客戶端知道如何建立與伺服器端對應服務的代理物件,
    //如果沒有設定該屬性,則以伺服器端的服務類名字作為 HubName 的預設值
    [HubName("chat")]
    public class ChatHub : Hub 
    {
        public void Send(string clientName, string message)
        {
            // Call the addSomeMessage method to update clients.
            Clients.All.addSomeMessage(clientName, message);
        }
    }
}

在上面的程式碼中,實現的服務很簡單,就是當一個客戶端呼叫Send方法向伺服器傳送message後,伺服器端負責將該 message廣播給所有的客戶端(也可以給特定組或特定客戶端),以實現聊天室的功能。

除了服務端可以向所有客戶端通知呼叫客戶端方法之外,還可以對其中想要傳送的客戶端進行限制。同時Clients這個屬性有很多動態成員供我們使用:

Clients.All:允許“呼叫”連線到此Hub上的所有客戶端的一個方法

Clients.AllExcept:表示該呼叫必須傳送給所有客戶端,但是除了那些作為引數的connectionId以外。這裡的引數可以是connectionId字串、陣列等

Clients.Caller 確定呼叫者的接收者是目前呼叫正在執行Hub方法的客戶端

Clients.Client:將對方法的呼叫傳送給指定connectionId的客戶端,引數可以是字串,也可以是陣列

Client.Others :代表所有已連線的客戶端,但是不包括正在呼叫該方法的客戶端。

在方法中可以通過訪問 this.Context.ConnectionId來獲得當前掉用方法的客戶端唯一識別符號

1)、HubName 這個特性是為了讓客戶端知道如何建立與伺服器端對應服務的代理物件,如果沒有設定該屬性,則以伺服器端的服務類名字作為 HubName 的預設值;

2)、ChatHub 繼承自 Hub,從下面 Hub 的介面圖可以看出:Hub 支援向發起請求者(Caller),所有客戶端(Clients),特定組(Group) 推送訊息。

3)、public void Send(string clientName, string message) 這個介面是被客戶端通過代理物件呼叫的;

4)、Clients 是 Hub 的屬性,表示所有連結的客戶端頁面,它和 Caller一樣是 dynamic,因為要直接對應到 Javascript 物件;

5)、Clients.All.addSomeMessage(clientName, message): 表示伺服器端呼叫客戶端的 addSomeMessage 方法,這是一個 Javascript 方法,從而給客戶端推送訊息。

4.2、配置啟動類

using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(SignalRTestProj.App_Start.ChartStartup))]

namespace SignalRTestProj.App_Start
{
    public class ChartStartup
    {
        public void Configuration(IAppBuilder app)
        {
            // 有關如何配置應用程式的詳細資訊,請訪問 https://go.microsoft.com/fwlink/?LinkID=316888
            //1、 PersistentConnection 方式配置
            //app.MapSignalR<ChatConnection>("/Connections/ChatConnection");

            //2、hub方式配置    
            app.MapSignalR();          
        }
    }
}

4.3、頁面程式碼實現

<h2>Hub Chat</h2>

<div>
    <input type="hidden" id="ClientName" value="@ViewBag.ClientName"/>
    <input type="text" id="msg" />
    <input type="button" id="broadcast" value="廣播" />
    <br />

    <h3>
        (<span id="MyClientName">@ViewBag.ClientName</span>):
    </h3>

    <ul id="messages"></ul>
</div>

@section scripts {
    <script src="~/Scripts/jquery-3.3.1.min.js"></script>
    <script src="~/Scripts/jquery.signalR-2.4.1.min.js"></script>
    <script src="~/signalr/hubs"></script>
    <script>
        $(function () {            
            var chat = $.connection.chat;
            var myClientName = $('#ClientName').val();            
            chat.client.addSomeMessage = function (clientName, message) {
                writeMsg('<b>' + clientName + '</b> 對大家說: ' + message, 'event-message');
            };

            $('#msg').focus();
            // 開始連線
            $.connection.hub.start().done(function () {
                $('#broadcast').click(function () {
                    // 呼叫send方法
                    chat.server.send(myClientName, $('#msg').val());                   
                    $('#msg').val('').focus();
                });
            });

            //寫訊息
            function writeMsg(eventLog, logClass) {
                var now = new Date();
                var nowStr = now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds();
                $('#messages').prepend('<li class="' + logClass + '"><b>' + nowStr + '</b> ' + eventLog + '.</li>');
            }
        });
    </script>
}

在上面的程式碼我們

1、首先獲取客戶端頁面的名字;

2、然後通過 $.connection.chat 建立對應伺服器端 Hub 類的代理物件 chat;

3、定義客戶端的 Javascript 方法 addSomeMessage,伺服器通過 dynamic 方式呼叫客戶端的該方法以實現推送功能。在這裡每當收到伺服器推送來的訊息,就在客戶端頁面的 messages 列表表頭插入該訊息。

4、當點選廣播按鈕時,客戶端通過代理物件呼叫伺服器端的 send 方法以實現向伺服器傳送訊息。

5、通過 $.connection.hub.start(); 語句開啟連結。

5、效果展示

6、程式碼下載

例項原始碼可以移步github下載,地址:https://github.com/yonghu86/SignalRTestProj

7、參考文章

  • 史上最全面的SignalR系列教程-1、認識SignalR

  • 史上最全面的SignalR系列教程-2、SignalR 實現推送功能-永久連線類實現方式

  • Real-time ASP.NET with SignalR

  • 微信公眾號開發系列-玩轉微信開發-目錄彙總

  • RDIFramework.NET — 基於.NET的快速資訊化系統開發框架 — 系列目錄

  • RDIFramework.NET ━ .NET快速資訊化系統開發框架 ━ 工作流程元件介紹

  • RDIFramework.NET框架SOA解決方案(集Windows服務、WinForm形式與IIS形式釋出)-分散式應用

  • RDIFramework.NET程式碼生成器全新V3.5版本釋出-重大升級


一路走來數個年頭,感謝RDIFramework.NET框架的支持者與使用者,大家可以通過下面的地址瞭解詳情。

RDIFramework.NET官方網站:http://www.rdiframework.net/

RDIFramework.NET官方部落格:http://blog.rdiframework.net/

同時需要說明的,以後的所有技術文章以官方網站為準,歡迎大家收藏!

RDIFramework.NET框架由海南國思軟體科技有限公司專業團隊長期打造、一直在更新、一直在升級,請放心使用!

歡迎關注RDIFramework.net框架官方公眾微信(微訊號:guosisoft),及時瞭解最新動態。

掃描二維碼立即關注