SignalR 实现web浏览器客户端与服务端的推送功能
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:持久性連接,用來解決長時間連接的能力,而且還可以由客戶端主動向服務器要求數據,而服務器端也不需要實現太多細節,只需要處理 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>
運行起來就是這個效果:
下面我們來展示 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 打開。
注意:SingalR 會自動生成一個siganlr/hub 的橋接js..,在本機使用localhost測試都不會有問題。當部署到IIS的時候會發生404錯誤,是由于被IIS誤判可能是虛擬目錄…,解決方法是在web.config加入一段:
<!-- 加入下面這一段-->
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true">
</modules>
</system.webServer>
參考:
- https://github.com/SignalR/SignalR/wiki/QuickStart-Persistent-Connections
- https://github.com/SignalR/SignalR/wiki/QuickStart-Hubs
實例代碼:MvcApplicationSignalR
總結
以上是生活随笔為你收集整理的SignalR 实现web浏览器客户端与服务端的推送功能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 文莱在世界地图的哪个位置(文莱在哪里世界
- 下一篇: 与非门(说一说与非门的简介)