摘要:[.NET] signalR 2.2 & VS2012 簡易開發教學
前言:
因工作上的需求,要實現一個可以即時對所有正在使用網頁的User發布訊息的廣播系統。
所以用signalR來實作此一功能,參考了很多網站,大部分都還是舊版的安裝方式並不太適合目前版本。
signalR簡介:
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 。
安裝:
安裝:
搜尋signalR->安裝
其餘相關套件會一併安裝,並自動加入參考和javascript。
開發&設定
先建立Owin類別檔Startup.cs 內容為:
using System;
using System.Threading.Tasks;
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(SignalRChat.Startup))]
namespace SignalRChat
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
// 如需如何設定應用程式的詳細資訊,請參閱 http://go.microsoft.com/fwlink/?LinkID=316888
//*********************************************************
app.MapSignalR(); //自己動手新增這一段,這是 SignalR v2版需要的。
//*********************************************************
}
}
}
接下來再新增一個 signalR Hub類別檔
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;
using System.Threading.Tasks;
using Microsoft.Owin;
public class signalRChat : Hub
{
// 呼叫所有使用者
//Clients.All.alertMessage(message);
// 呼叫除了自己的使用者
//Clients.Others.alertMessage(message);
// 呼叫所有使用者除了某個 ConnectionId 的使用者
//Clients.AllExcept(Context.ConnectionId).alertMessage(message);
// 呼叫自己
//Clients.Caller.alertMessage(message);
// 呼叫特定使用者
//Clients.Client(Context.ConnectionId).alertMessage(message);
// 呼叫群組使用者
//Clients.Group(groupId).alertMessage(message);
//宣告靜態類別,來儲存上線清單
public static class UserHandler
{
public static Dictionary ConnectedIds = new Dictionary();
}
//使用者連線時呼叫
public void userConnected(string name, string groupId)
{
//進行編碼,防止XSS攻擊
name = HttpUtility.HtmlEncode(name);
//新增目前使用者至上線清單
UserHandler.ConnectedIds.Add(Context.ConnectionId, name);
//新增使用者至群組
Groups.Add(Context.ConnectionId, groupId);
}
//發送訊息給所有人
public void sendAllMessage(string message)
{
message = HttpUtility.HtmlEncode(message);
Clients.All.alertMessage(message); //alertMessage 為client端 function名稱
}
//發送訊息至特定使用者
public void sendMessage(string connectId, string message)
{
message = HttpUtility.HtmlEncode(message);
Clients.Clients(connectId).alertMessage(message); //alertMessage 為client端 function名稱
}
//發送訊息至特定使用者名稱
public void sendMessageByName(string userName, string message)
{
message = HttpUtility.HtmlEncode(message);
var connectId = UserHandler.ConnectedIds.Where(p => p.Value == userName).FirstOrDefault().Key;
Clients.Clients(connectId).alertMessage(message); //alertMessage 為client端 function名稱
}
//發送訊息至群組
public void sendGroupMessage(string groupId, string message)
{
message = HttpUtility.HtmlEncode(message);
Clients.Group(groupId).alertMessage(message); //alertMessage 為client端 function名稱
}
//當使用者斷線時呼叫
public override Task OnDisconnected(bool stopCalled)
{
//當使用者離開時,移除在清單內的 ConnectionId
Clients.All.removeList(Context.ConnectionId);
UserHandler.ConnectedIds.Remove(Context.ConnectionId);
return base.OnDisconnected(stopCalled);
}
}
我是統一放在App_code資料夾底下,方便修改
因新版本使用Owin所以在web.config要設定內容為
<appSettings>
<!--signalR-->
<add key="owin:AutomaticAppStartup" value="true"/>
<add key="owin:AppStartup" value="SignalRChat.Startup" /><!--value同Startup.cs的namespace.class-->
</appSettings>
server端的設定
接下來在前端網頁
<script src="Scripts/jquery-1.11.0.min.js" type="text/javascript"></script>
<script src="Scripts/jquery.signalR-2.2.0.js" type="text/javascript"></script>
<%--很重要的參考,一定要加這一行,這之前一定要先參考jQuery.js與signalR.js--%>
<script src='<%= ResolveClientUrl("~/signalr/hubs") %>'></script>
<script type="text/javascript">
signalRChat = $.connection.signalRChat;
if (signalRChat) { //判斷是否有建立成功
registerClientMethods(signalRChat);
$.connection.hub.start().done(function () {
signalRChat.server.userConnected(groupId, userId); //向後端註冊 Clinet端(前端)使用者的 function
});
}
//*** 向後端的Hub,註冊 Clinet端(前端)的 function
function registerClientMethods(chatHub) {
// 定義client端的javascript function,供server端hub,透過dynamic的方式,呼叫所有Clients的javascript function
chatHub.client.alertMessage = function (message) {
//當server端調用addMessage時,將server push的message資料,alert出來
alert(message);
};
}
//**********************************************(end)
$.connection.hub.disconnected(function () {
setTimeout(function () {
$.connection.hub.start().done(function () {
signalRChat.server.userConnected(groupId, userId); //斷線後重新註冊
});
}, 5 * 1000); // Restart connection after 5 seconds.
});
</script>
<script src='<%= ResolveClientUrl("~/signalr/hubs") %>'></script>
上面這段也可改用以下方式
var signalRUrl = window.location.origin;
if (!signalRUrl) { //部分ie 抓不到 window.location.origin
signalRUrl = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port : '');
}
$.ajax({
url: signalRUrl + "/signalr/hubs",
dataType: "script",
async: false
});
到這邊總算是建立完成,接下來就可以開始使用了
當想要對其他人發送訊息時,直接再js呼叫sever端function就可以了
例如跟全部的人說 你上線了
signalRChat.server.sendAllMessage('hello, ' + userId + ' 上線了');
使用時有幾點要特別注意
signalR 太久沒用還是會斷線的。
所以發送訊息前 可以先用以下語法檢查目前的連線狀態
signalRChat.connection.state //Object {connecting: 0, connected: 1, reconnecting: 2, disconnected: 4}
或者是紀錄一下錯誤訊息
signalRChat.server.sendAllMessage('hello, ' + userId + ' 上線了').fail(function (error) {
console.log('Send signalR failed. Error: ' + error);
});
總結:
基本範例就照上面的作就OK了
因為.NET把signalR這功能封裝的很好,很簡單就可以學會並應用。