SignalR QuickStart

SignalR 是一個集成的客戶端與服務器庫,基於瀏覽器的客戶端和基於 ASP.NET 的服務器組件可以藉助它來進行雙向多步對話。 換句話說,該對話可不受限制地進行單個無狀態請求/響應數據交換;它將繼續,直到明確關閉。 對話通過永久連接進行,允許客戶端向服務器發送多個消息,並允許服務器做出相應答覆,值得注意的是,還允許服務器向客戶端發送異步消息。它和AJax類似,都是基於現有的技術。本身是一個複合體。一般情況下,SignalR會使用Javascript的長輪詢( long polling),實現客戶端和服務端通信。在WebSockets出現以後,SignalR也支持WebSockets通信。當然SignalR也使用了服務端的任務並行處理技術以提高服務器的擴展性。它的目標整個 .NET Framework 平臺,它也不限 Hosting 的應用程序,而且還是跨平臺的開源項目,支持Mono 2.10+,覺得它變成是 Web API 的另一種實作選擇,但是它在服務端處理聯機的功能上比 ASP.NET MVC 的 Web API 要強多了,更重要的是,它可以在 Web Form 上使用。

SignalR 內的客戶端庫 (.NET/JavaScript) 提供了自動管理的能力,開發人員只需要直接使用 SignalR 的 Client Library 即可,同時它的 JavaScript 庫可和 jQuery 完美整合,因此能直接與像 jQuery 或 Knockout.js 一起使用。

SignalR內部有兩類對象:

· Persistent Connection(HTTP持久鏈接):持久性連接,用來解決長時間連接的能力,而且還可以由客戶端主動向服務器要求數據,而服務器端也不需要實現太多細節,只需要處理 PersistentConnection 內所提供的五個事件:OnConnected, OnReconnected, OnReceived, OnError 和 OnDisconnect 即可。

· Hub:信息交換器,用來解決 realtime 信息交換的功能,服務器端可以利用 URL 來註冊一個或多個 Hub,只要連接到這個 Hub,就能與所有的客戶端共享發送到服務器上的信息,同時服務器端可以調用客戶端的腳本,不過它背後還是不離 HTTP 的標準,所以它看起來神奇,但它並沒有那麼神奇,只是 JavaScript 更強,強到可以用像 eval() 或是動態解釋執行的方式,允許 JavaScript 能夠動態的加載與執行方法調用而己。

SignalR 將整個交換信息的行爲封裝得非常漂亮,客戶端和服務器全部都使用 JSON 來溝通,在服務器端聲明的所有 hub 的信息,都會一般生成 JavaScript 輸出到客戶端,.NET 則是依賴 Proxy 來生成代理對象,這點就和 WCF/.NET Remoting 十分類似,而 Proxy 的內部則是將 JSON 轉換成對象,以讓客戶端可以看到對象。

下面我們來針對Persistent Connection和Hub 做個Demo試試:

新建一個ASP.NET MVC項目MvcApplicationSignalR,通過Nuget添加SignalR的包。

新建一個類MyConnection 繼承自 PersistentConnection ,引用SignalR命名空間,重寫OnReceivedAsync 的方法,並要求 SignalR 對傳入的信息做廣播

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using SignalR; 
using System.Threading.Tasks;

namespace MvcApplicationSignalR 

   public  class MyConnection : PersistentConnection

    { 
       protected override Task OnReceivedAsync(IRequest request, string connectionId, string data) 
        { 
            // Broadcast data to all clients 
            data = string.Format("數據是:{0} 時間是:{1}", data, DateTime.Now.ToString()); 
            return Connection.Send(connectionId, data); 
        }

    } 
}

接着在 Global.asax 中加入對應路由信息,這會由 SignalR 的路由表來處理 Metadata 的輸出工作,紅色部分代碼:

protected void Application_Start() 

    RouteTable.Routes.MapConnection<MyConnection>("echo", "echo/{*operation}");

 

這樣服務器端就完成了。現在我們在項目中Master、View (Home/Index),然後加入必要的代碼:

<head> 
    <meta charset="utf-8" /> 
    <title>@ViewBag.Title</title> 
    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" /> 
    <script src="@Url.Content("~/Scripts/jquery-1.6.4.min.js")" type="text/javascript"></script> 
    <script src="@Url.Content("~/Scripts/modernizr-1.7.min.js")" type="text/javascript"></script> 
    <script src="@Url.Content("~/Scripts/jquery.signalR-0.5.2.min.js")" type="text/javascript"></script> 
</head>

@{ 
    ViewBag.Title = "Home Page"; 

<script type="text/javascript"> 
    $(function () { 
        var connection = $.connection('echo');

        connection.received(function (data) { 
            $('#messages').append('<li>' + data + '</li>'); 
        });

        connection.start();

        $("#broadcast").click(function () { 
            connection.send($('#msg').val()); 
        }); 
        $("#btnStop").click(function () { 
            connection.stop(); 
        }); 
    });

</script> 
<h2>@ViewBag.Message</h2> 
<input type="text" id="msg" /> 
<input type="button" id="broadcast" value="發送" /> 
<input type="button" id="btnStop" value="停止" /> 
<ul id="messages"> 
</ul>

運行起來就是這個效果:

image

下面我們來展示 SignalR 的另一個功能:由服務器端調用客戶端的 JavaScript 腳本的功能,而這個功能的要求必須是要實現成 Hub 的模式,因此我們可以順便看到如何實現一個 Hub 類型的 SignalR 應用程序。

向項目中加入一個類Chat繼承自 Hub 類 (這是 Hub 應用程序的要求) :

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using SignalR.Hubs; 
using System.Threading.Tasks; 
using System.Threading;

namespace MvcApplicationSignalR 

   [HubName("geffChat")] 
   public class Chat : Hub  
   { 
       public void SendMessage(string message) 
       { 
           Clients.sendMessage(message); 
       } 
   } 
}

這段程序代碼的用意是,在連接進到 Hub 時,將連接代碼加到聯機用戶的集合中,等會就會使用到,因爲我們會依照客戶端的 ID 來調用客戶端腳本。

1. HubName:這個 atttibute 代表 client 端要如何建立對應 server 端對象的 proxy object。通過 HubName , server 端的 class name纔不會被 client 綁死。如果沒有設定,則會以 server 端 class name 爲 HubName 默認值。

2. 繼承 Hub:繼承 Hub 之後,很多對應的設計就都不用寫了,我們只需要把注意力放在 client 如何送 request 給 server的 hub , server 如何通知 client 即可。

3. public void SendMessage(string message) ,就像 WebService Method 或 PageMethod 一般, client 端通過 proxy object ,可以直接調用 server 端這個方法。後續會介紹到如何在頁面上使用。

4. Clients 屬性:代表所有有使用 Chat 的頁面。而 Clients 的型別是 dynamic ,因爲要直接對應到 JavaScript 的對象。

5. Clients.sendMessage(message):代表 server 端調用 Clients 上的 sendMessage 方法,也就是 JavaScript 的方法。

6. 總結: Chat 對象職責就是當 client 端調用SendMessage() 方法後,要把這個 message ,送給所有 client 頁面上呈現。以達到聊天室的功能。

服務端的做完了,開始製作客戶端,同樣在Home/Index頁面上增加以下html代碼

<%--很重要的一個參考,一定要加,且在這一行之前,一定要先參考jQuery.js與signalR.js--%> 
<script src="@Url.Content("~/signalr/hubs")" type="text/javascript"></script>

@{ 
    ViewBag.Title = "Home Page"; 

<script type="text/javascript"> 
    $(function () { 
        var connection = $.connection('/echo');    

        connection.received(function (data) { 
            $('#messages').append('<li>' + data + '</li>'); 
        });

        connection.start();

        $("#broadcast").click(function () { 
            connection.send($('#msg').val()); 
        }); 
        $("#btnStop").click(function () { 
            connection.stop(); 
        });

        // 建立對應server端Hub class的對象,請注意geffChat的第一個字母要改成小寫 
        var chat = $.connection.geffChat;

        // 定義client端的javascript function,供server端hub,通過dynamic的方式,調用所有Clients的javascript function 
        chat.sendMessage = function (message) { 
            //當server端調用sendMessage時,將server push的message數據,呈現在wholeMessage中 
            $('#wholeMessages').append('<li>' + message + '</li>'); 
        };

        $("#send").click(function () { 
            //調用叫server端的Hub對象,將#message數據傳給server 
            chat.sendMessage($('#message').val()); 
            $('#message').val(""); 
        });

        //把connection打開 
        $.connection.hub.start();

    });

</script> 
<h2>@ViewBag.Message</h2> 
<input type="text" id="msg" /> 
<input type="button" id="broadcast" value="發送" /> 
<input type="button" id="btnStop" value="停止" /> 
<ul id="messages"> 
</ul>

<div> 
    <input type="text" id="message" /> 
    <input type="button" id="send" value="發送" /> 
    <div> 
        聊天室內容: 
        <br /> 
        <ul id="wholeMessages"> 
        </ul> 
    </div> 
</div>

1. 先引用 jQuery 與 signalR 的 js 文件。

2. 很重要的一個步驟:加入一個 js 引用,其路徑爲「根目錄/signalr/hubs」。 SignalR 會建立相關的 JavaScript,放置於此。

3. 通過 $.connection.『server 端的 HubName』,即可建立對應該 hub 的 proxy object。要注意,首字母需小寫。

4. 定義 client 端上,供 server 端通知的 JavaScript function,這邊的例子是 sendMessage。

5. 當按下發送按鈕時,調用 server 端的 SendMessage() 方法,只需要直接通過 proxy object 即可。要注意,首字母需小寫。

6. 記得透過 $.connection.hub.start() ,把 connection 打開。

image

注意:SingalR 會自動生成一個siganlr/hub 的橋接js..,在本機使用localhost測試都不會有問題。當部署到IIS的時候會發生404錯誤,是由於被IIS誤判可能是虛擬目錄…,解決方法是在web.config加入一段:

<!-- 加入下面這一段-->

<system.webServer>

<validation validateIntegratedModeConfiguration="false" />

<modules runAllManagedModulesForAllRequests="true">

</modules>

</system.webServer>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章