SignalR 再次超越你對 Web 的想像 - 建立即時互動的 Web

                         作者:王育民 - Dino

第一次聽到 SignalR 技術是 Scott Hanselman 於 2011 年的一次產品介紹,Scott 以實際的火力展示了使用 SingalR 技術實作即時股市資訊看板,讓 ASP.NET 開發人員得到相當大的興奮與鼓舞。SignalR 被設計為適合用來開發任何一種即時 (real-time) 類型的 One ASP.NET 應用程式,在最新的版本 client 端甚至已經跨出瀏覽器的框架邁入是手持式設備,SignalR將以極低的進入門檻,讓 .NET 開發人員進入即時互動的 real-time 世界。

為何 SignalR 一現身就鋒芒畢露

近一、兩年來 HTML5 的發展可說是沸沸揚揚,在這之中你也許聽過 HTML5 規劃給瀏覽器與伺服器之間進行全雙工通訊的 WebSocket 通訊協定,並提供了 WebSocket API 這一套完整的 API 設計,在規格的部分,WebSocket 通訊協定已經於 2011 年被 IETF (國際網路工程研究團隊) 定為標準 RFC 6455,而 WebSocket API 則被 W3C 定為標準。目前各平台的瀏覽器的主流版本皆已經支援 HTML5 WebSocket / WebSocket API。(參考 - https://tools.ietf.org/html/rfc6455)

WebSocket / WebSocket API 企圖解決開發者長久以來實作伺服器推送技術 (Server Push) 幾乎都仰賴輪詢 (Polling) 的作法所造成的明顯缺點,將使得伺服器接受到太多請求,產生伺服器資源的過度佔用以及頻寬的浪費。

當然,開發人員是非常神奇的!生命自會找到出路,在沒有 AJAX 的時代變出了利用 IFrame 傳遞訊息的方法;在輪詢 (Polling) 這種相當耗費伺服器資源的設計模式下,想出了長輪詢 (Long Polling) 的解決方法,有效的減少了連線的請求。這些技術產生與伺服器之間方便又接近及時的相關技巧,統稱為 Comet Programming[1]

 

圖 2 輪詢 (Polling) 與長輪詢 (Long Polling) 的 request 模型

 

圖 3 實際上比較常使用的長輪詢 (Long Polling) 模型,此為循序圖 (Sequence diagram)

Comet Programming 的基本概念:

l   採用輪詢 (Polling) 還是長輪詢 (Long Polling) 行為

l   透過 XmlHttpRequest 或是 IFrame 技術

然而在 HTML5 規格建議書推出以後,WebSocket 真正地擦亮了開發人員的眼鏡,所謂內行看門道外行看熱鬧,無不引頸期盼 WebSocket API 的到來,因為在這之前Comet Programming 早已把開發人員搞得又煩又累,一方面要讓瀏覽器產生恆久的伺服器連線,斷線還要設法自動重試連結,一方面還要避免不當的 JavaScript 實作產生了記憶體洩漏 (memory leak) 問題,現在有了 WebSocket 這麼強大的 API,開發者卻是憂喜參半?

追究其原因,軟體開發終究是為了要讓用戶可以很方便的使用,把話說得更白了,就是盡量不要要求使用者的執行環境,能跨新舊瀏覽器,才堪稱軟體有足夠的親和力J。在這樣的前提下,開發者既要懂得 Comet Programming 也想善用 WebSocket,另外還得讓他們在適當的場合下,出來露露臉,這無疑加重了開發人員的負擔,技術門檻蓋得奇高,真是令人生畏,在開發完我們的即時報價網站之前,恐怕以先成了 Comet 的老骨頭。

而 SignalR 的出現讓 ASP.NET 開發者得到救贖,兼容的通訊協定設計將 Comet Programming 概念與 WebSocket 技術都放在 SignalR 整個通訊框架裡面,尤其會優先在瀏覽器支援的情況下使用效能與傳輸效率表現都比較好的 WebSocket 技術,以避免 Comet 對於伺服器產生的無謂資源浪費。

 

圖 4

SignalR 的任務是提供開者者一套非常易於使用的高階 API ,用來實現伺服器端與瀏覽器間的遠程程序呼叫 (RPC ,Remote Procedure Call) ,在這個架構下伺服器端以 .NET 開發,瀏覽器端則主要是以 JavaScript 開發,SignalR 提供了優異的連線/ 斷線管理以及擴充模型、連線/ 斷線的事件通知,在訊息溝通的本質上則提供了令人期待的內建群組連線、還有相關的身份驗證檢查機制。

SignalR 會針對目前執行的瀏覽器進行判斷,找到與伺服器間最適合的建立連線方式,SignalR 會優先的選用 WebSocket 技術與伺服器溝通,當然伺服器上的通訊協定管理方式也內含在 ASP.NET SignalR 的組件庫中,開發人員就不需要針對目前走的是 Web Socket、Polling 還是 Long Polling 進行特別的處理,所有的 code 都透過 ASP.NET SignalR高階的 API 進行訊息傳遞。

 

圖 5 SignalR 技術在伺服器連線,選用最佳通訊技術的執行期間示意圖

SignalR 與 Visual Studio 2013

伴隨著即將來到的 Visual Studio 2013 正式版,新版 SignalR 揭露了以下新的特性:

支援 iOS 與 Android

使用 Xamarin 以及 MonoTouch / MonoDroid 設計的應用程式,可以透過 Xaramin Store 取得 RTW 版的 SignalR 2.0版。

支援多種 .NET 用戶端

l   .NET 4.5

l   Silverlight 5

l   WinRT (Windows Store App)

l   Windows Phone 8

Self hosting

透過安裝 Microsoft.AspNet.SignalR.SelfHost 套件,使得 SignalR 有能力執行於 Console 或 Service 等具有 OWIN 規格的應用程式中。

支援 client 舊於 server 版本的部署

過往執行期間必須確保 SignalR client 與 server 端版本必須相同的執行要求,在新的 SignalR 設計中得到不錯的改善,現在 SignalR 支援較舊的 SignalR client 對較新的 SignalR server 發出請求,這有助於解決 Mobile 應用程式的開發存在應用程式更新時間差[2]這種難以避免的棘手問題。

備註:但是仍然無法以較新的 SignalR client 連結較舊的 SignalR server。

 

舊版 client API

新版 client API

舊版 server API

V

X

新版 server API

V

V

表 1 實際部署環境下新舊 client /server API 版本的支援狀況

如何獲得 ASP.NET SignalR

在 Visual Studio 2013 / Visual Studio 2012 Update 2 中,SignalR 已被正式掛上 ASP.NET SignalR 的產品名稱,成為 ASP.NET 開發者們在尋求 real-time web 解決方案時的首選,SignalR 開發者可以隨時透過 NuGet 搜尋並取得這項技術。

說明:SignalR v2 目前 RC1,SignalR 團隊於 NuGet 所提供的新版 SignalR v2 範例,目前仍無法正常安裝於 ASP.NET 專案上 (範例套件內容為空),而 GitHub 上團隊所提供的相關範例 (https://github.com/SignalR/Samples) 也仍以 v1 為主,為求讀者能輕易上手、易於取得起見,本文後記練習部分以 v1 為主,NuGet 套件請抓取穩定版本。

 

圖 6 以 NuGet 取得 SingalR 組件

 

圖 7 ASP.NET SignalR 與相依組件

安裝 SignalR 時,核心的套件為 Microsoft.AspNet.SignalR,但 NuGet 會同時安裝相依的組件,組件簡要說明如下:

l   Microsoft.AspNet.SignalR

l   Microsoft.AspNet.SignalR.Core

l   Microsoft.AspNet.SignalR.Owin

l   Microsoft.AspNet.SignalR.JS

l   Microsoft.AspNet.SignalR.SystemWeb

除了 SignalR 已經發展得與 ASP.NET 更加的緊密了,同時間也與整個 One ASP.NET同步支援了 OWIN 規範,讓 SignalR 優異的即時通訊能力與其他 One ASP.NET 產品一樣,不受限於只能執行在 IIS 上。

Microsoft.AspNet.SignalR.Sample

SignalR 提供了一份立刻可以嘗鮮的好範例,您可以使用 Visual Studio 2013 開啟新的 ASP.NET 專案 (筆者使用的是 MVC 範本),利用 NuGet 自行下載官方提供的 SignalR 範例,請利用 NuGet 搜尋 “Microsoft.AspNet.SignalR.Sample” 或者 “SignalR Sample”,安裝 SignalR Sample 時 NuGet 會幫你一併加入所有 SignalR 技術的相依組件,如圖 8 利用 NuGet 下載官方提供的 SignalR 範例 (Microsoft.AspNet.SignalR.Sample)。

 

圖8 利用 NuGet 下載官方提供的 SignalR 範例 (Microsoft.AspNet.SignalR.Sample)

tips:

當您使用 Visual Studio 2013 Preview 新增了 ASP.NET 專案,並且於開啟專案後下載 Microsoft.AspNet.SignalR.Sample 範例,可能會遇到執行階段的問題,其中預設的 SignalR.StockTicker.js 可能會出現瀏覽器端執行階段錯誤,原因是無法正確載入相關的 .js 檔案,這是 mime type 不正確的緣故,請先做以下修改,讓範例可以順利執行:

    <!--

    <script src="../bundles/jquery"></script>

    <script src="../bundles/jquerycolor"></script>

    -->

    <script src="../Scripts/jquery-1.9.1.js"></script>

    <script src="../Scripts/jquery.color-2.1.2.js"></script>

    <script src="../Scripts/jquery.signalR-1.1.3.js"></script>

    <!--

    <script src="../signalr/hubs.js"></script>

    <script src="SignalR.StockTicker.js"></script>

    -->

    <script>

        (function () {

            $.getScript("../signalr/hubs", function () {

                $.getScript("SignalR.StockTicker.js");

            });

        })();

    </script>

筆者寫文測試時發現,可能是因為Microsoft.AspNet.SignalR.Sample 的版本比新版的 SignalR 舊,或許因此產生錯誤的組態,範例才發生這樣的問題,藉由筆者提供的修改,可以暫時避免掉無法順利執行的錯誤,下一波的 Sample 更新應該會注意到這個問題才是J。

表 2 小秘訣,解決安裝 SignalR Sample 但卻無法順利執行的方式

SignalR Sample 專案執行後,是一份模擬反應股市即時狀態的表格,看到圖 9 SignalR Sample 的執行畫面就表示您已經順利的進入了 SignalR 的世界,恭喜你喔!

 

圖9 SignalR Sample 於瀏覽器中的執行畫面

ASP.NET SignalR 編程模型

SignalR 主要藉由 “Hub” 這個核心類別,為伺服器端以及瀏覽器搭建出溝通的管道,開發 SignalR 應用程式的第一步,就是由新增 Hub Class開始。

 

圖 10 新增一個通訊端,必先由實作 SignalR Hub Class 開始 

using Microsoft.AspNet.SignalR;

 

namespace WebApplication

{

    public class ChatHub : Hub

    {

        public void Send(string name, string message)

        {

            Clients.All.notify(name, message);

        }

    }

}

表3 SignalR Hub 實作範例

如同表 3 SignalR Hub 實作範例所顯示,撰寫 SignalR 應用程式的第一步是新增一個自己的 Hub 並繼承自 SignalR Hub 類別,Hub 是個相當特殊的類別,負責產生與前端 JavaScript function 綁定的相關定義。

伺服器端要傳送一個訊息到瀏覽器,你可以在自訂的 Hub 類別方法,如 Send,用 Clients 屬性並且決定訊息佈達的範圍 (全部、群組或是除了自己以外),當然前提是他們也得要透過 SignalR 連接到系統中,一開始我們都會直接接觸到 All 的範圍,用一張簡單的圖 11 一個運用 SignalR 實作的網路聊天室,執行期間的通訊示意來說明 All 訊息傳送的對象,是所有已經透過 SignalR Hub 連結的瀏覽器。

 

圖11 一個運用 SignalR 實作的網路聊天室,執行期間的通訊示意

Send 方法除了透過 Client 呼叫 JavaScript 的 notify 之外,它本身也會被 SignalR 製作為瀏覽器端可以呼叫的 JavaScript 程式碼,讓瀏覽器內的程式可以直接呼叫 send 方法 (在 JavaScript 端方法名稱會被轉換成 JavaScript 慣用的小寫命名方式),透通呼叫到位於後端的 Send method。

與前端 JavaScript code 產生對應的 Hub 類別,繼承自Microsoft.AspNet.SignalR.Hub 類別,SignalR v1/v2 比較,Hub 的程式寫作方式沒有太大的異動,依舊是非常簡潔的。

參考資料

  1. 1.          SignalR.net - https://signalr.net/
  2. 2.          ASP.NET SignalR - https://www.asp.net/signalr
  3. 3.          github: SignalrR - https://github.com/SignalR/SignalR
  4. 4.          ASP.NET for Mobile, One ASP.NET and Realtime ASP.NET with SignalRr - Video of Scott Hanselman's talks in Russia - https://www.hanselman.com/blog/ASPNETForMobileOneASPNETAndRealtimeASPNETWithSignalrVideoOfScottHanselmansTalksInRussia.aspx
  5. 5.          JosephJ, Browser 與 Server 持續同步的作法介紹 (Polling, Comet, Long Polling, WebSocket) - https://josephj.com/entry.php?id=358
  6. 6.          Microsoft MVP 91, [.NET] SignalR簡介 - 建立 realtime 的網站 - https://www.dotblogs.com.tw/hatelove/archive/2012/07/01/signalr-introduction-about-realtime-website.aspx
  7. 7.          Microsoft MVP小朱, [.NET] SignalR: 一個改變 Web 應用開發觀念的開發方式 - https://www.dotblogs.com.tw/regionbbs/archive/2012/07/01/introduce.to.signalr.aspx

[1] Comet 一詞為彗星,Comet Programming 取自經典 Long Polling 方法的一個生動描述,Long Polling對伺服器拉出了一條長長的恆久連線,看起來就像是彗星尾巴一樣!

[2]包含 App 上架審核期間的不確定、App 未被用戶端更新等不可控因素。

 

延伸閱讀