C# 使用SignalR實現訊息通知

Denny輝發表於2019-11-08

背景:Web端需要能實時接收到訊息推送,當客戶有新訊息來時,在客戶端的右下角進行彈框提醒。

什麼是signalR?

Asp.net SignalR是微軟為實現實時通訊的一個類庫。一般情況下,signalR會使用JavaScript的長輪詢(long polling)的方式來實現客戶端和伺服器通訊,隨著Html5中WebSockets出現,SignalR也支援WebSockets通訊。另外SignalR開發的程式不僅僅限制於宿主在IIS中,也可以宿主在任何應用程式,包括控制檯,客戶端程式和Windows服務等,另外還支援Mono,這意味著它可以實現跨平臺部署在Linux環境下。

signalR內部有兩類物件:

Http持久連線(Persisten Connection)物件:用來解決長時間連線的功能。還可以由客戶端主動向伺服器要求資料,而伺服器端不需要實現太多細節,只需要處理PersistentConnection 內所提供的五個事件:OnConnected, OnReconnected, OnReceived, OnError 和 OnDisconnect 即可。
Hub(集線器)物件:用來解決實時(realtime)資訊交換的功能,服務端可以利用URL來註冊一個或多個Hub,只要連線到這個Hub,就能與所有的客戶端共享傳送到伺服器上的資訊,同時服務端可以呼叫客戶端的指令碼。SignalR將整個資訊的交換封裝起來,客戶端和伺服器都是使用JSON來溝通的,在服務端宣告的所有Hub資訊,都會生成JavaScript輸出到客戶端,.NET則依賴Proxy來生成代理物件,而Proxy的內部則是將JSON轉換成物件。

SignalR將整個資訊的交換封裝起來,客戶端和伺服器都是使用JSON來溝通的,在服務端宣告的所有Hub資訊,都會生成JavaScript輸出到客戶端,.NET則依賴Proxy來生成代理物件,而Proxy的內部則是將JSON轉換成物件。

客戶端和服務端的具體互動情況如下圖所示:

基本流程如圖:

其實說白點SignalR其實就是微軟自己封裝好的實現即時通訊的一個類庫

如何使用:

Nuget引入 Microsoft.AspNet.SignalR 系列 2.4.1

新增完signalR你可以在 Scripts 資料夾下看到自動新增了兩個js檔案:

向專案中新增一個signalR集線器(V2)命名為ServerHub:

在剛剛新建的ServerHub.cs 中寫入 一下程式碼:

//*********************************************************************************
//Description:自定義擴充套件一個訊息通知類庫模組>集線器
//Author:DennyHui
//Create Date: 2019年10月15日18:39:33
//*********************************************************************************
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;

namespace Fisk.DataWithReportManage.AutoTask
{
    /// <summary>
    /// 訊息通知集線器  2019年10月16日12:28:08  Dennyhui
    /// </summary>
    [HubName("serverhub")]
    public class ServerHub:Hub
    {
        /// <summary>
        /// 傳送訊息 2019年10月16日12:28:18  Dennyhui
        /// </summary>
        /// <param name="message"></param>
        public void SendMsg(string id,string title, string message,string poptype)
        {
            //呼叫所有客戶端的sendMessage方法(sendMessage有2個引數)  
            //Clients.All.SendMessage("測試");
            //Clients.All.broadcastMessage("測試");
            //Clients.All.notify("測試");
            var hubContext = GlobalHost.ConnectionManager.GetHubContext<ServerHub>();//此處的“ServerHub”需要和當前的類名一直
            hubContext.Clients.All.sendMessage(id,title,message, poptype); //使用者呼叫客戶端的函式 
            //Clients.All.sendMessage(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), "測試");
        }
        /// <summary>
        /// 例項化  2019年10月16日12:28:31  Dennhui
        /// </summary>
        public void Init() { }
    }
}

 

如果你的mvc專案是不進行身份驗證的那種吧,必須得新增一個Startup 類.      如果沒有這個類,請新增,不然的話專案執行不起來的,具體程式碼如下:

using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(SignalRQuickStart.Startup))]

namespace SignalRQuickStart
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // 有關如何配置應用程式的詳細資訊,請訪問 http://go.microsoft.com/fwlink/?LinkID=316888
            // 配置集線器
            app.MapSignalR();
        }
    }
}

在Control 裡新建一個MessageAction方法,在Message檢視裡新增程式碼如下:

 

@{
    ViewBag.title = "SignaIR聊天視窗";
}
    <div class="container">
        <input type="text" id="message" />
        <input type="button" id="sendmessage" value="Send" />
        <input type="hidden" id="displayname" />
        <ul id="messageBox"></ul>
    </div>
@section scripts
{
   <script src="~/Scripts/jquery.signalR-2.2.1.min.js"></script>
   <script src="~/signalr/hubs"></script>
    <script>
        $(function () {
            //引用自動生成的集線器代理
            var chat = $.connection.serverHub;
             //定義伺服器呼叫的客戶端sendMessage來顯示新訊息
            chat.client.sendMessage = function (name, message)
            {
                //向頁面新增訊息
                $("#messageBox").append('<li><strong style="color:green">'+htmlEncode(name)+'</strong>:'+htmlEncode(message)+'</li>');
            }
            //設定焦點到輸入框
            $('#message').focus();
            //開始連線伺服器
            $.connection.hub.start().done(function () {
                $('#sendmessage').click(function () {
                    //呼叫伺服器端集線器的Send方法
                    chat.server.sendMsg($('#message').val());
                    //清空輸入框資訊並獲取焦點
                    $("#message").val('').focus();
                })
            })
        });
        //為顯示的訊息進行html編碼
        function htmlEncode(value)
        {
            var encodeValue = $('<div/>').text(value).html();
            return encodeValue;
        }
    </script>
}

 

         //訊息通知  2019年10月15日18:38:56  Dennyhui
        function  SignalRMessage () {
            //toastr.info("向頁面新增訊息  ", "新訊息");
            var NowDateNoticeList = window.WebNotificationList;
            //引用自動生成的集線器代理  
            var chat = $.connection.serverhub;
            //定義伺服器呼叫的客戶端sendMessage來顯示新訊息  
            //此處的“sendMessage”需要和後臺傳送訊息的方法名一致
            chat.client.sendMessage = function (id, title, message, poptype) {
                
                // do somethings
               
            }
            //集線器開始工作
            $.connection.hub.start().done(function () {
                chat.server.init();
            });

好了,一個signalR簡單的入門的例子就ok了.

在任何一個web 頁面中傳送的訊息所有的 頁面都會接收到該訊息。這種應用在IM系統非常廣泛常見。

當然signalR並不侷限於這種B/S模式的訊息推送,在C/S 同樣也能應用,目前我們公司xamarin android所用的就是這個signalR實現的PC之間、PC與移動端、移動端與移動端之間的交流,使用之後會發現的確挺方便的。

有人可能感覺很鬱悶了,在檢視中引入 這段js有什麼作用?也並有寫啊。

注意!,這是虛擬目錄,也就是你在OWIN Startup中註冊的地址

<script src="~/signalr/hubs"></script>

這個路徑你在專案裡面是找不到的!

其實在伺服器端宣告的所有Hub資訊,最終都會生成JavaScript輸出到客戶端,其實谷歌瀏覽器中F12 ,在Sources你就可以看到寫的原始碼了:

來看一下在這種B/S 模式中 signalR是如何執行的吧。首先程式開始的時候,Web頁面就已經與signalR的服務建立連線。

$.connection.hub.start() 意思就是有signalR服務建立連線

.done 函式表示連線成功後為傳送的按鈕繫結一個單擊事件

傳送訊息的方法:chat.server.sendMsg($('#message').val())

在ServerHub重寫一個 OnConnected 方法來監控客戶端的連線情況,的確程式執行的時候web頁面就已經開始建立連線了,在除錯的時候可以在輸入中看到 "客戶端連線成功!

一個簡單的如何使用signalR就是這麼多,用法很廣泛,當然還可以進行擴充套件。

可以使用Quartz這個元件和Signalr搭配進行定時排程傳送訊息

有興趣的朋友可以去看下如何使用Quartz來進行定時排程。

後面我也會更新一篇關於如何使用Quartz進行定時排程Job的文章。

相關文章