[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/