[SignalR] 實作聊天室功能
安裝Nuget
1.先建立一個空白Web專案。2.Nuget—>Microsoft ASP.NET SignalR,此套件會順便裝好其他必要套件
新增Hub類別
Hub類別如下:
public class codingChatRoomHub : Hub
{
// 宣告靜態類別,來儲存上線清單
public static class UserHandler
{
public static Dictionary<string, string> ConnectedIds = new Dictionary<string, string>();
}
public void UserConnected(string name)
{
string message = " 歡迎使用者 " + name + " 加入聊天室 ";
// 發送訊息給除了自己的其他使用者
Clients.Others.addList(Context.ConnectionId, name);
Clients.Others.hello(message);
// 發送訊息至自己,並且取得上線清單
Clients.Caller.getList(UserHandler.ConnectedIds.Select(p => new { id = p.Key, name = p.Value }));
// 新增目前使用者至上線清單
UserHandler.ConnectedIds.Add(Context.ConnectionId, name);
}
// 發送訊息給所有人
public void SendAllMessage(string message)
{
message = HttpUtility.HtmlEncode(message);
var name = UserHandler.ConnectedIds.Where(p => p.Key == Context.ConnectionId).FirstOrDefault().Value;
string msg = name + " Say:" + message;
Clients.All.sendAllMessage(msg);
}
public void SendMessage(string toId, string message)
{
var fromName = UserHandler.ConnectedIds.Where(p => p.Key == Context.ConnectionId).FirstOrDefault().Value;
string msg = fromName + " <span style='color:red'> 悄悄的對你說 </span> : " + message;
Clients.Client(toId).sendMessage(msg);
}
public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled)
{
// 當使用者離開時,移除在清單內的 ConnectionId
Clients.All.removeList(Context.ConnectionId);
UserHandler.ConnectedIds.Remove(Context.ConnectionId);
return base.OnDisconnected(stopCalled);
}
}
程式重點:
- UserConnected方法,讓使用者在前諯註冊後叫用,並將名字放在一個靜態集合(此部分實際運用可以改成用資料庫)
- Clients類別提供的通知對象方法
- All:通知全部
- Others:通知全部但排除自己
- Caller:通知自己
- Client: 通知特定的ID
- 叫用以上方法後會回傳dynamic型別的代理物件,用來叫用前端script的方法,例如 Client.All.sendMessage,紅字部份為動態方法
- 覆寫OnDisconnected方法,使用者離線時從集合移合並通知前端
加入Owin啟動類別為SignalR註冊Route
在1.1版是在Global.asax的RouteTable註冊,但在2.x版是透過Owin的IAppBuilder擴充方法來註冊
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(SignalRPractice.Startup))]
namespace SignalRPractice
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
// 如需如何設定應用程式的詳細資訊,請參閱 http://go.microsoft.com/fwlink/?LinkID=316888
app.MapSignalR();
}
}
}
Html內容:chatRoom.html
此部份有使用Bootstrap美化一下..
<div class="row">
<div class="col-sm-10">
<div class="panel panel-primary">
<div class="panel-heading">Chating Content <span id="userName" class="glyphicon glyphicon-user pull-right"> Hi ! </span></div>
<div id="messageBox" class="panel-body">
<ul id="messageList"></ul>
</div>
</div>
<div id="bar">
<div class="col-sm-4">
<select id="box" class="form-control">
<option value="all"> 所有人 </option>
</select>
</div>
<div class="col-sm-4">
<input type="text" id="message" class="form-control" />
</div>
<div class="col-sm-4">
<input type="button" id="send" value=" 發送 " />
</div>
</div>
</div>
<div class="col-sm-2">
<div class="panel panel-info">
<div class="panel-heading">Online User</div>
<div class="panel-body">
<div id="chatList">
<p> 上線清單 </p>
<ul id="list"></ul>
</div>
</div>
</div>
</div>
</div>
引用JavaScript
此地方要注意的是"/signalr/hubs"的引用,此引用目錄在執行時期才會動態產生,實體檔案並不會存在。ps:要放在jQuery及signalR之後
<script src="Scripts/jquery-2.1.1.min.js"></script>
<script src="Scripts/jquery.signalR-2.1.2.min.js"></script>
<script src="/signalr/hubs"></script>
JavaScript內容
<script>
var userID = "";
$(function () {
while (userID.length == 0) {
userID = window.prompt("請輸入使用者名稱");
if (!userID)
userID = "";
}
$("#userName").append(userID).show();
//建立與Server端的Hub的物件,注意Hub的開頭字母一定要為小寫
var chat = $.connection.codingChatRoomHub;
//取得所有上線清單
chat.client.getList = function (userList) {
var li = "";
$.each(userList, function (i, data) {
li += "<li id='" + data.id + "'><a href='#'><span class='glyphicon glyphicon-user'> " + data.name + "</span></a></li>";
})
$("#list").html(li);
registerListClick();
}
//新增一筆上線人員
chat.client.addList = function (id, name) {
var li = "<li id='" + id + "'><a href='#'><span class='glyphicon glyphicon-user'> " + name + "</span></a></li>";
$("#list").append(li);
registerListClick();
}
//移除一筆上線人員
chat.client.removeList = function (id) {
$("#" + id).remove();
}
//全體聊天
chat.client.sendAllMessage = function (message) {
$("#messageList").append("<li>" + message + "</li>");
}
//密語聊天
chat.client.sendMessage = function (message) {
$("#messageList").append("<li>" + message + "</li>");
}
chat.client.hello = function (message) {
$("#messageList").append("<li>" + message + "</li>");
}
//將連線打開
$.connection.hub.start().done(function () {
//當連線完成後,呼叫Server端的userConnected方法,並傳送使用者姓名給Server
chat.server.userConnected(userID);
});;
$("#send").click(function () {
var to = $("#box").val();
//當to為all代表全體聊天,否則為私密聊天
if (to == "all")
chat.server.sendAllMessage($("#message").val());
else
chat.server.sendMessage(to, $("#message").val());
$("#message").val("");
});
})
function registerListClick() {
$("#list li").unbind("click");
$("#list li").on("click", function () {
var $this = $(this);
var id = $this.attr("id");
var text = $this.text();
//防止重複加入密語清單
if ($("#box").has("." + id).length > 0) {
$("#box").find("[class=" + id + "]").attr({ "selected": "selected" });
}
else {
var option = "<option></option>"
$("#box").append(option).find("option:last").val(id).text(text).attr({ "selected": "selected" }).addClass(id);
}
});
}
</script>
程式重點:
- 透過$.connection建立Hub物件(codingChatRoomHub)
- 叫用Server端的類別、方法,第一個字需改成小寫
- hub物件叫用Server均透過屬性server:chat.server.sendMessage
- hub物件建立client端方法讓server端叫用:chat.client.removeList=function(){...}
測試程式
瀏覽chatRoom.html,輸入你的名稱
開啟另一視窗再加入另一個User"Guest”
發送訊息
參考來源
http://msdn.microsoft.com/zh-tw/library/dn535720.aspx
http://msdn.microsoft.com/zh-tw/library/dn535725.aspx
http://www.asp.net/signalr/overview/releases/upgrading-signalr-1x-projects-to-20
範例程式
https://github.com/kimx/SignalRPractice/