Asp.net SignalR的應用並實現群聊功能的執行個體詳解

來源:互聯網
上載者:User
這篇文章主要為大家分享了Asp.net SignalR應用並實現群聊功能,具有一定的參考價值,感興趣的小夥伴們可以參考一下

ASP.NET SignalR 是為 ASP.NET 開發人員提供的一個庫,可以簡化開發人員將即時 Web 功能添加到應用程式的過程。即時 Web 功能是指這樣一種功能:當所串連的用戶端變得可用時伺服器代碼可以立即向其推送內容,而不是讓伺服器等待用戶端請求新的資料。(來自官方介紹。)

SignalR官網

-1、寫這篇的原因

在上篇文章B/S(Web)即時通訊解決方案中,並沒有詳情介紹SignalR,所以另起一篇專門介紹SignalR,本文的側重點是Hub功能。

0、先看最終實現效果

github.com/Emrys5/SignalRGroupChatDemo

1、準備工作

1.1、在NuGet上首先下載SignalR的包。

1.2、配置Owin與SignalR

1.2.1、建立Startup類,註冊SignalR

public class Startup { public void Configuration(IAppBuilder app) {  app.MapSignalR(); } }

然後在web.config配置Startup類,在configuration=>appSettings節點中添加

<add key="owin:AppStartup" value="SignalRChat.App_Start.Startup"/>

1.2.2、在頁面引入SignalR的js

1、由於SignalR前端是基於jQuery的,所以頁面需引入jQuery。

2、引入SignalR的js 。

3、引入最重要的hubs js,這個js其實並不存在,SignalR會反射擷取所有供用戶端調用的方法放入hubs js中。

<script src="~/Scripts/jquery-1.10.2.js"></script><script src="~/Scripts/jquery.signalR-2.2.1.min.js"></script> <script src="~/signalr/hubs"></script>

1.2.3、建立GroupChatHub類,並繼承Hub抽象類別

在hub類中的方法就是提供給用戶端調用的js方法。

在js中就可以用signalr調用SendMsg。

[HubName("simpleHub")] public class SimpleHub : Hub {  public void SendMsg(string msg) { } }

這樣基本上前期準備工作就做完了,後面就是具體的操作。

2、原理與簡單的編程

其實原理如果簡單點理解就很簡單,因為http是無狀態的,所以每次請求以後都會與伺服器取消連結,那就是說用戶端可以很容易找到伺服器,但是伺服器如果想給你用戶端發送訊息就比較麻煩,如果不明白的可以參考上一篇文章B/S(Web)即時通訊解決方案。

SignalR就很好的解決了這個問題,也就說實現了實現了瀏覽器與伺服器的全雙工系統通訊。

2.1、用戶端至服務端(B=>S)

用戶端代碼

<script type="text/javascript">  var ticker = $.connection.simpleHub; $.connection.hub.start(); $("#btn").click(function () { // 連結完成以後,可以發送訊息至服務端 ticker.server.sendMsg("需要發送的訊息"); }); </script>

服務端代碼

[HubName("simpleHub")] public class SimpleHub : Hub { public void SendMsg(string msg) {  // 擷取連結id  var connectionId = Context.ConnectionId;   // 擷取cookie  var cookie = Context.RequestCookies; } }

其中SimpleHub就是我們定義的繼承Hub類SimpleHub,然後我們可以用特性HubName進行重新命名。

然後開始連結。

在連結完成以後,我們就可以調用在SimpleHub類中調用的方法。這就就很簡單的實現了用戶端至服務端發送訊息。

我們還可以在Context中擷取我們想要的東西,比如連結id,cookie等。

2.2、服務端至用戶端(S=>B)

服務端代碼

[HubName("simpleHub")] public class SimpleHub : Hub { public void SendMsg(string msg) {  Clients.All.msg("發送給用戶端的訊息");  } }

用戶端代碼

<script type="text/javascript"> var ticker = $.connection.groupChatHub; $.connection.hub.start(); ticker.client.msg = function (data) { console.log(data); } </script>

這裡示範了怎麼發送訊息至用戶端,也是SignalR比較重要的功能,這裡有兩個問題需要解決。

問題一、這裡是發送訊息給所有連著的用戶端,如果是單個用戶端或者是一批用戶端應該怎麼發送。

問題二、我們在調用msg給個用戶端發送訊息時是在接收訊息以後做的反饋,然後發送訊息給用戶端,這樣就很類似ajax了,服務端並沒有主動給用戶端發送訊息。

解決:

問題一、Clients可以給特性的一群或者一個用戶端發送訊息

// 所有人Clients.All.msg("發送給用戶端的訊息"); // 特定 cooectionIdClients.Client("connectionId").msg("發送給用戶端的訊息");// 特定 groupClients.Group("groupName").msg("發送給用戶端的訊息");

這是比較常用的三個,當然還有很多,比如AllExcept,Clients。

在SignalR2.0中還添加了Others,OthersInGroup,OthersInGroups等等。

問題二、我們可以在需要發送訊息的地方調用GlobalHost.ConnectionManager.GetHubContext<SimpleHub>().Clients中擷取Clients。擷取Clients並發送訊息我們最好寫成單例模式,因為這種需求很符合單例,群聊中有詳細的代碼。

3、SignalR實現群聊

以上的介紹和代碼已經可以實現b=>s和s=>b了,那實現群聊和單獨聊天就比較簡單了。

由於功能比較簡單,所有我把使用者名稱存到了cookie裡,也就說第一次進來時需要設定cookie。

還有就是在hub中要實現OnConnected、OnDisconnected和OnReconnected,然後在方法中設定使用者和connectionid和統計線上使用者,以便聊天使用。

hub代碼

/// <summary> /// SignalR Hub 群聊類 /// </summary> [HubName("groupChatHub")] // 標記名稱供js調用 public class GroupChatHub : Hub { /// <summary> /// 使用者名稱 /// </summary> private string UserName {  get  {  var userName = Context.RequestCookies["USERNAME"];  return userName == null ? "" : HttpUtility.UrlDecode(userName.Value);  } } /// <summary> /// 線上使用者 /// </summary> private static Dictionary<string, int> _onlineUser = new Dictionary<string, int>(); /// <summary> /// 開始串連 /// </summary> /// <returns></returns> public override Task OnConnected() {  Connected();  return base.OnConnected(); } /// <summary> /// 重新連結 /// </summary> /// <returns></returns> public override Task OnReconnected() {  Connected();  return base.OnReconnected(); } private void Connected() {  // 處理線上人員  if (!_onlineUser.ContainsKey(UserName)) // 如果名稱不存在,則是新使用者  {  // 加入線上人員  _onlineUser.Add(UserName, 1);  // 向用戶端發送線上人員  Clients.All.publshUser(_onlineUser.Select(i => i.Key));  // 向用戶端發送加入聊天訊息  Clients.All.publshMsg(FormatMsg("系統訊息", UserName + "加入聊天"));  }  else  {  // 如果是已經存在的使用者,則把線上連結的個數+1  _onlineUser[UserName] = _onlineUser[UserName] + 1;  }  // 加入Hub Group,為了發送單獨訊息  Groups.Add(Context.ConnectionId, "GROUP-" + UserName); } /// <summary> /// 結束串連 /// </summary> /// <param name="stopCalled"></param> /// <returns></returns> public override Task OnDisconnected(bool stopCalled) {  // 人員連結數-1  _onlineUser[UserName] = _onlineUser[UserName] - 1;  // 判斷是否斷開了所有的連結  if (_onlineUser[UserName] == 0)  {  // 移除線上人員  _onlineUser.Remove(UserName);  // 向用戶端發送線上人員  Clients.All.publshUser(_onlineUser.Select(i => i.Key));  // 向用戶端發送退出聊天訊息  Clients.All.publshMsg(FormatMsg("系統訊息", UserName + "退出聊天"));  }  // 移除Hub Group  Groups.Remove(Context.ConnectionId, "GROUP-" + UserName);  return base.OnDisconnected(stopCalled); } /// <summary> /// 發送訊息,供用戶端調用 /// </summary> /// <param name="user">使用者名稱,如果為0,則是發送給所有人</param> /// <param name="msg">訊息</param> public void SendMsg(string user, string msg) {  if (user == "0")  {  // 發送給所有使用者訊息  Clients.All.publshMsg(FormatMsg(UserName, msg));  }  else  {  //// 發送給自己訊息  //Clients.Group("GROUP-" + UserName).publshMsg(FormatMsg(UserName, msg));  //// 發送給選擇的人員  //Clients.Group("GROUP-" + user).publshMsg(FormatMsg(UserName, msg));  // 發送給自己訊息  Clients.Groups(new List<string> { "GROUP-" + UserName, "GROUP-" + user }).publshMsg(FormatMsg(UserName, msg));  } } /// <summary> /// 格式化發送的訊息 /// </summary> /// <param name="name"></param> /// <param name="msg"></param> /// <returns></returns> private dynamic FormatMsg(string name, string msg) {  return new { Name = name, Msg = HttpUtility.HtmlEncode(msg), Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }; } }

js代碼

<script type="text/javascript"> $(function () {  // 連結hub  var ticker = $.connection.groupChatHub;  $.connection.hub.start();  // 接收服務端發送的訊息  $.extend(ticker.client, {  // 接收聊天訊息  publshMsg: function (data) {   $("#msg").append("<li><span class='p'>" + data.Name + ":</span>" + data.Msg + " <span class='time'>" + data.Time + "</span></li>")   $("#msg").parents("p")[0].scrollTop = $("#msg").parents("p")[0].scrollHeight;  },  // 接收線上人員,然後加入Select,以供單獨聊天選中  publshUser: function (data) {   $("#count").text(data.length);   $("#users").empty();   $("#users").append('<option value="0">所有人</option>');   for (var i = 0; i < data.length; i++) {   $("#users").append('<option value="' + data[i] + '">' + data[i] + '</option>')   }  }  });  // 發送訊息按鈕  $("#btn-send").click(function () {  var msg = $("#txt-msg").val();  if (!msg) {   alert('請輸入內容!'); return false;  }  $("#txt-msg").val('');  // 主動發送訊息,傳入發送給誰,和發送的內容。  ticker.server.sendMsg($("#users").val(), msg);  }); }); </script>

html代碼

<h2> 群聊系統(<span id="count">1</span>人線上):@ViewBag.UserName</h2><p style="overflow:auto;height:300px"> <ul id="msg"></ul></p><select id="users" class="form-control" style="max-width:150px;"> <option value="0">所有人</option></select><input type="text" onkeydown='if (event.keyCode == 13) { $("#btn-send").click() }' class="form-control" id="txt-msg" placeholder="內容" style="max-width:400px;" /><br /><button type="button" id="btn-send">發送</button>

這樣就訊息了群聊和發送給特定的人聊天功能。

3.1、封裝主動發送訊息的單例

/// <summary> /// 主動發送給使用者訊息,單例模式 /// </summary> public class GroupChat { /// <summary> /// Clients,用來主動發送訊息 /// </summary> private IHubConnectionContext<dynamic> Clients { get; set; } private readonly static GroupChat _instance = new GroupChat(GlobalHost.ConnectionManager.GetHubContext<GroupChatHub>().Clients); private GroupChat(IHubConnectionContext<dynamic> clients) {  Clients = clients; } public static GroupChat Instance {  get  {  return _instance;  } } /// <summary> /// 主動給所有人發送訊息,系統直接調用 /// </summary> /// <param name="msg"></param> public void SendSystemMsg(string msg) {  Clients.All.publshMsg(new { Name = "系統訊息", Msg = msg, Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }); } }

如果需要發送訊息,直接調用SendSystemMsg即可。

GroupChat.Instance.SendSystemMsg("訊息");

4、結語

啥也不說了直接源碼

github.com/Emrys5/SignalRGroupChatDemo

相關關鍵詞:
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.