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>

參考:

實例代碼:MvcApplicationSignalR


免責聲明!

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



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