SignalR實現消息推送,包括私聊、群聊、線上所有人接收消息(源碼)

来源:http://www.cnblogs.com/cyzf/archive/2017/11/09/7808798.html
-Advertisement-
Play Games

一、關於SignalR 1、簡介:Signal 是微軟支持的一個運行在 Dot NET 平臺上的 html websocket 框架。它出現的主要目的是實現伺服器主動推送(Push)消息到客戶端頁面,這樣客戶端就不必重新發送請求或使用輪詢技術來獲取消息。 可訪問其官方網站:https://githu ...


一、關於SignalR

        1、簡介:Signal 是微軟支持的一個運行在 Dot NET 平臺上的 html websocket 框架。它出現的主要目的是實現伺服器主動推送(Push)消息到客戶端頁面,這樣客戶端就不必重新發送請求或使用輪詢技術來獲取消息。

可訪問其官方網站:https://github.com/SignalR/ 獲取更多資訊。

   2、SignalR 的實現機制與 .NET WCF 或 Remoting 是相似的,都是使用遠程代理來實現。在具體使用上,有兩種不同目的的介面:PersistentConnection 和 Hubs,其中 PersistentConnection 是實現了長時間的 Javascript 輪詢(類似於 Comet),Hub 是用來解決實時信息交換問題,它是利用 Javascript 動態載入執行方法實現的。SignalR 將整個連接,信息交換過程封裝得非常漂亮,客戶端與伺服器端全部使用 JSON 來交換數據。

下麵就 Hubs 介面的使用來講講整個流程:

  (1),在伺服器端定義對應的 hub class;

  (2),在客戶端定義 hub class 所對應的 proxy 類;

  (3),在客戶端與伺服器端建立連接(connection);

  (4),然後客戶端就可以調用 proxy 對象的方法來調用伺服器端的方法,也就是發送 request 給伺服器端;

  (5),伺服器端接收到 request 之後,可以針對某個/組客戶端或所有客戶端(廣播)發送消息。

       以上這些都是關註大神們瞭解的。

二、具體使用

  1、建立一個mvc項目 SignalR通訊

  

  2、安裝SignalR

    (1)、在SignalR通訊 項目下安裝 SignalR(找到程式包管理器控制台,輸入:Install-Package Microsoft.AspNet.SignalR)

        安裝成功後系統會自動生成一個Scripts文件夾,裡面存放對應的js文件,如圖

  

  3、安裝好環境以後。那麼接下來我們就開始搭建我們的環境及編寫相應的代碼

    (1)、新建一個SignalR集線器ServerHub,如圖

  

    並編寫以下代碼

 1 public class ServerHub : Hub
 2     {
 3         private static readonly char[] str =
 4         {
 5             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
 6             'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
 7             'w', 'x', 'y', 'z',
 8             'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
 9             'W', 'X', 'Y', 'Z'
10         };
11 
12         /// <summary>
13         /// 消息發送介面
14         /// </summary>
15         /// <param name="message"></param>
16         public void SendMsg(string message)
17         {
18             var name = GenerateUserName(4);
19 
20             // 調用所有客戶端的sendMessage方法
21             Clients.All.sendMessage(name, message);
22         }
23 
24         /// <summary>
25         /// 產生隨機用戶
26         /// </summary>
27         /// <param name="length">用戶名長度</param>
28         /// <returns></returns>
29         public static string GenerateUserName(int length)
30         {
31             var newRandom = new StringBuilder(62);
32             var rd = new Random();
33             for (var i = 0; i < length; i++)
34             {
35                 newRandom.Append(str[rd.Next(62)]);
36             }
37             return newRandom.ToString();
38         }

 

    (2)、創建一個Startup類,(如果創建項目是有這個類。就不用添加了)添加代碼如下 

 public void Configuration(IAppBuilder app)
        {
            // 配置集線器
            app.MapSignalR();
        }

    (3)、添加Home控制器及視圖Index(此步驟不截圖)

    (4)、添加Index視圖代碼  如下

 1 @{
 2     Layout = "~/Views/Shared/_Layout.cshtml";
 3     ViewBag.Title = "聊天視窗";
 4 }
 5 
 6 <h2>Index</h2>
 7 
 8 <div class="container">
 9     <input type="text" id="message" />
10     <input type="button" id="sendmessage" value="Send" />
11     <input type="hidden" id="displayname" />
12     <ul id="discussion"></ul>
13 </div>
14 
15 @section scripts
16 {
17 <script src="~/Scripts/jquery-1.6.4.min.js"></script>
18     <!--引用SignalR庫. -->
19     <script src="~/Scripts/jquery.signalR-2.2.2.min.js"></script>
20     <!--引用自動生成的SignalR 集線器(Hub)腳本.在運行的時候在瀏覽器的Source下可看到 -->
21     <script src="~/signalr/hubs"></script>
22 
23     <script>
24         $(function () {
25             // 引用集線器代理
26             var chat = $.connection.serverHub;
27             // 定義伺服器端調用的客戶端sendMessage來顯示新消息
28 
29             chat.client.sendMessage = function (name, message) {
30                 // 向頁面添加消息
31                 $('#discussion').append('<li><strong>' + htmlEncode(name)
32                     + '</strong>: ' + htmlEncode(message) + '</li>');
33             };
34 
35             // 設置焦點到輸入框
36             $('#message').focus();
37             // 開始連接伺服器
38             $.connection.hub.start().done(function () {
39                 $('#sendmessage').click(function () {
40                     // 調用伺服器端集線器的SendMsg方法
41                     chat.server.sendMsg($('#message').val());
42                     // 清空輸入框信息並獲取焦點
43                     $('#message').val('').focus();
44                 });
45             });
46         });
47 
48         // 為顯示的消息進行Html編碼
49         function htmlEncode(value) {
50             var encodedValue = $('<div />').text(value).html();
51             return encodedValue;
52         }
53     </script>
54 }

  4、完成以上步驟之後,我們的SignalR算是簡單的完成。讓我們來看下製作結果吧

    (1)、如果出現如下錯誤,請刪除紅框里的代碼

    

    成功之後的結果,如圖

    

    你以為完了嘛?還沒有,別急往下看

三、頁面有優化及私聊、群聊、線上所有人接收消息的實現

  1、發送所有線上人員

    (1)、在layer官網下載layer前端js和ui(在我上一篇的文章中有下載地址,或者直接百度搜索layer),放到你的項目中,在這裡我們就不直接說頁面代碼的編寫部分,直接看下我們的效果圖,如下

     

    (2)、在完成聊天之前。我們還需要做什麼,對做登錄,在這裡自動生成的用戶已經不能滿足我們接下來的需求了(登錄教程跳過)直接看登錄成功過後的界面

    

    

    這樣看起來就美觀多了,其實線上所有人聊天的功能,就是剛剛我們實現那個功能是一樣的,沒有任何的變化(只是美觀了下),看看聊天結果吧

    

      

  

    2、群聊

      (1)、首先我們的建一個群聊的實體(UserGroup)和房間實體(ChatRoom),如下圖

       

 

    (2)、在我們建好的ServerHub類里編寫如下代碼(具體實現看源碼)

  1 public static ChatContext DbContext = new ChatContext();
  2 
  3         // 重寫Hub連接斷開的事件  (斷線時調用)
  4         public override Task OnDisconnected(bool stopCalled)
  5         {
  6             // 查詢用戶
  7             var user = DbContext.Users.FirstOrDefault(u => u.UserId == Context.ConnectionId);
  8 
  9             if (user != null)
 10             {
 11                 // 刪除用戶
 12                 DbContext.Users.Remove(user);
 13 
 14                 // 從房間中移除用戶
 15                 foreach (var item in user.Rooms)
 16                 {
 17                     RemoveUserFromRoom(item.RoomName);
 18                 }
 19             }
 20             return base.OnDisconnected(stopCalled);
 21         }
 22         
 23         // 為所有用戶更新房間列表
 24         public void UpdateRoomList()
 25         {
 26             var itme = DbContext.Rooms.Select(p => new { p.RoomName });
 27             var jsondata = JsonHelper.ToJsonString(itme.ToList());
 28             Clients.All.getRoomlist(jsondata);
 29         }
 30 
 31         /// <summary>
 32         /// 加入聊天室
 33         /// </summary>
 34         public void JoinRoom(string roomName)
 35         {
 36             // 查詢聊天室
 37             var room = DbContext.Rooms.Find(p => p.RoomName == roomName);
 38 
 39             // 存在則加入
 40             if (room == null) return;
 41 
 42             // 查找房間中是否存在此用戶
 43             var isExistUser = room.Users.FirstOrDefault(u => u.UserId == Context.ConnectionId);
 44 
 45             // 不存在則加入
 46             if (isExistUser == null)
 47             {
 48                 var user = DbContext.Users.Find(u => u.UserId == Context.ConnectionId);
 49                 user.Rooms.Add(room);
 50                 room.Users.Add(user);
 51 
 52                 // 將客戶端的連接ID加入到組裡面
 53                 Groups.Add(Context.ConnectionId, roomName);
 54 
 55                 //調用此連接用戶的本地JS(顯示房間)
 56                 Clients.Client(Context.ConnectionId).joinRoom(roomName);
 57             }
 58             else
 59             {
 60                 Clients.Client(Context.ConnectionId).showMessage("請勿重覆加入房間!");
 61             }
 62         }
 63 
 64         /// <summary>
 65         /// 創建聊天室
 66         /// </summary>
 67         /// <param name="roomName"></param>
 68         public void CreateRoom(string roomName)
 69         {
 70             var room = DbContext.Rooms.Find(a => a.RoomName == roomName);
 71             if (room == null)
 72             {
 73                 var cr = new ChatRoom
 74                 {
 75                     RoomName = roomName
 76                 };
 77 
 78                 //將房間加入列表
 79                 DbContext.Rooms.Add(cr);
 80 
 81                 // 本人加入聊天室
 82                 JoinRoom(roomName);
 83                 UpdateRoomList();
 84             }
 85             else
 86             {
 87                 Clients.Client(Context.ConnectionId).showMessage("房間名重覆!");
 88             }
 89         }
 90 
 91         public void RemoveUserFromRoom(string roomName)
 92         {
 93             //查找房間是否存在
 94             var room = DbContext.Rooms.Find(a => a.RoomName == roomName);
 95 
 96             //存在則進入刪除
 97             if (room == null)
 98             {
 99                 Clients.Client(Context.ConnectionId).showMessage("房間名不存在!");
100                 return;
101             }
102 
103             // 查找要刪除的用戶
104             var user = room.Users.FirstOrDefault(a => a.UserId == Context.ConnectionId);
105             // 移除此用戶
106             room.Users.Remove(user);
107             //如果房間人數為0,則刪除房間
108             if (room.Users.Count <= 0)
109             {
110                 DbContext.Rooms.Remove(room);
111             }
112 
113             Groups.Remove(Context.ConnectionId, roomName);
114 
115             //提示客戶端
116             Clients.Client(Context.ConnectionId).removeRoom("退出成功!");
117         }
118 
119         /// <summary>
120         /// 給房間內所有的用戶發送消息
121         /// </summary>
122         /// <param name="room">房間名</param>
123         /// <param name="message">信息</param>
124         public void SendMessage(string room, string message)
125         {
126             // 調用房間內所有客戶端的sendMessage方法
127             // 因為在加入房間的時候,已經將客戶端的ConnectionId添加到Groups對象中了,所有可以根據房間名找到房間內的所有連接Id
128             // 其實我們也可以自己實現Group方法,我們只需要用List記錄所有加入房間的ConnectionId
129             // 然後調用Clients.Clients(connectionIdList),參數為我們記錄的連接Id數組。
130             Clients.Group(room, new string[0]).sendMessage(room, message + " " + DateTime.Now);
131         }

    (3)、在Home控制器里創建GroupUser視圖並添加如下代碼

  1 @{
  2     Layout = null;
  3 }
  4 
  5 <!DOCTYPE html>
  6 
  7 <html>
  8 <head>
  9     <meta name="viewport" content="width=device-width" />
 10     <title>Index</title>
 11     <script src="~/Scripts/jquery-1.10.2.min.js"></script>
 12     <script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script>
 13     <script src="~/Scripts/layer/layer.js"></script>
 14     <!--這裡要註意,這是虛擬目錄,也就是你在OWIN Startup中註冊的地址-->
 15     <script src="/signalr/hubs"></script>
 16 
 17     <script type="text/javascript">
 18         var chat;
 19         var roomcount = 0;
 20 
 21         $(function() {
 22             chat = $.connection.serverHub;
 23             chat.client.showMessage = function(message) {
 24                 alert(message);
 25             };
 26             chat.client.sendMessage = function(roomname, message) {
 27                 $("#" + roomname).find("ul").each(function() {
 28                     $(this).append('<li>' + message + '</li>');
 29                 });
 30             };
 31             chat.client.removeRoom = function(data) {
 32                 alert(data);
 33             };
 34             chat.client.joinRoom = function (roomname) {
 35                 var html = '<div style="float:left; margin-left:360px; border:double; height:528px;width:493px" id="' + roomname + '" roomname="' + roomname + '"><button onclick="RemoveRoom(this)">退出</button>\
 36                                     ' + roomname + '房間\
 37                                                 聊天記錄如下:<ul>\
 38                                                 </ul>\
 39                                     <textarea class="ChatCore_write" id="ChatCore_write" style="width:400px"></textarea> <button onclick="SendMessage(this)">發送</button>\
 40                                     </div>';
 41                 $("#RoomList").append(html);
 42             };
 43 
 44             //註冊查詢房間列表的方法
 45             chat.client.getRoomlist = function(data) {
 46                 if (data) {
 47                     var jsondata = $.parseJSON(data);
 48                     $("#roomlist").html(" ");
 49                     for (var i = 0; i < jsondata.length; i++) {
 50                         var html = ' <li>房間名:' + jsondata[i].RoomName + '<button roomname="' + jsondata[i].RoomName + '" onclick="AddRoom(this)">加入</button></li>';
 51                         $("#roomlist").append(html);
 52                     }
 53                 }
 54             };
 55             // 獲取用戶名稱。
 56             $('#username').html(prompt('請輸入您的名稱:', ''));
 57 
 58             $.connection.hub.start().done(function() {
 59                 $('#CreatRoom').click(function() {
 60                     chat.server.createRoom($("#Roomname").val());
 61                 });
 62             });
 63         });
 64 
 65         function SendMessage(btn) {
 66             var message = $(btn).prev().val();
 67             var room = $(btn).parent();
 68             var username = $("#username").html();
 69             message = username + ":" + message;
 70             var roomname = $(room).attr("roomname");
 71             chat.server.sendMessage(roomname, message);
 72             $(btn).prev().val('').focus();
 73         }
 74 
 75         function RemoveRoom(btn) {
 76             var room = $(btn).parent();
 77             var roomname = $(room).attr("roomname");
 78             chat.server.removeUserFromRoom(roomname);
 79         }
 80 
 81         function AddRoom(roomname) {
 82             var data =$(roomname).attr("roomname");
 83             chat.server.joinRoom(data);
 84         }
 85 
 86     </script>
 87 </head>
 88 <body>
 89     <div>
 90         <div>名稱:<p id="username"></p></div>
 91         輸入房間名:
 92         <input type="text" value="聊天室1" id="Roomname" />
 93         <button id="CreatRoom">創建聊天室</button>
 94     </div>
 95     <div style="float:left;border:double">
 96         <div>房間列表</div>
 97         <ul id="roomlist"></ul>
 98     </div>
 99     <div id="RoomList">
100     </div>
101 </body>
102 </html>

    (4)、做好以上步驟之後,主要的功能已經實現,那麼接下來我們看下效果 如下

    點擊發送群聊之後出現如圖所示

    

    並創建自己的用戶名

    我們在創建自己的用戶名之後,可以選擇自己創建房間或者加入已有的房間,如下圖

    

    

  3、私聊

 

    (1)、私聊我們在這裡就不多說了。實現原理和群里差不多。都是找到對應的人員id就ok,直接上圖看結果

    

    

源碼請加qq群:460362190 裡面有更多的開源項目哦,歡迎加入討論

如果你還滿意請點擊關註和推薦,謝謝    

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在C#中通過使用方法來獲取返回值時,通常只能得到一個返回值。因此,當一個方法需要返回多個值的時候,就需要用到ref和out,那麼這兩個方法區別在哪兒呢? MSDN: ref 關鍵字使參數按引用傳遞。其效果是,當控制權傳遞迴調用方法時,在方法中對參數所做的任何更改都將反映在該變數中。若要使用 ref  ...
  • ASP.NET Core 是一個跨平臺的,高性能,開源框架,用於生成基於雲且連接 Internet 的新式應用程式。我們可以使用 ASP.NET Core: 生成 Web 應用和服務、IoT 應用和移動後端。 在 Windows、macOS 和 Linux 上使用喜愛的開發工具。 部署到雲或本地 在 ...
  • 在剛接觸C#的時候由於公司使用的就是Oracle資料庫,那麼C#怎麼連接Oracle資料庫就成了首要去掌握的知識點了。在那時沒有ODP.NET,但visual studio卻對Oralce資料庫的調用進行了集成,就是下圖中的這個,儘管現在使用這個的時候visual studio提醒過時的,但在那時卻 ...
  • 直接進入正題。 在HomeController中有一個NotFound的Action方法。 public ActionResult NotFound() { return View(); } 對應的視圖 @{ Layout = null; } <!DOCTYPE html> <html> <head ...
  • 創建證書-生成CSR(Certificate Sign Request): 填寫證書基本信息 接下來我們就可以看到創建的證書簽名請求信息(CSR): 為我們剛纔創建的CSR簽名: 簽名的意思是說通過證書簽發機構給我們生成證書, 在剛纔的CSR信息鏈接的部分有Request Sign鏈接, 點擊之後目 ...
  • 1.生成驗證碼字元串 2.繪製干擾線 3.生成驗證碼 4.前段獲取驗證碼 5.後臺驗證 ...
  • 最近的一個項目,要求導出Visio圖紙,因為是建築類的,所以,需要設置牆壁,門,房間等信息的參數。 拿牆壁為例,選中牆壁模型,右鍵屬性,會彈出以下對話框。 需要設置牆長、牆壁厚度等一些列信息。 現在C#操作Visio里例子比較少,所以,花了好久,都沒有看到有用的帖子,直到今天下午,在Bing里發現了 ...
  • 近乎產品下載地址:http://www.jinhusns.com ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...