天天看點

(附源碼)vue3.0+.NET6實作聊天室(實時聊天SignalR)

參考文章

搭建文章

gitte源碼

線上體驗

可以注冊兩個号來測試

示範圖:

(附源碼)vue3.0+.NET6實作聊天室(實時聊天SignalR)

一. 整體介紹

  介紹SignalR一種通訊模型Hub(中心模型,或者叫集線器模型),調用這個模型寫好的方法,去發送消息。

  内容有:

    ①:Hub模型的方法介紹

    ②:伺服器端代碼介紹

    ③:前端vue3 安裝并調用後端方法

    ④:聊天室樣例

整體流程:

1、進入網站 -> 調用連接配接 SignalR 的方法

(附源碼)vue3.0+.NET6實作聊天室(實時聊天SignalR)
(附源碼)vue3.0+.NET6實作聊天室(實時聊天SignalR)

2、與好友發送消息 -> 調用 SignalR 的自定義方法

(附源碼)vue3.0+.NET6實作聊天室(實時聊天SignalR)
(附源碼)vue3.0+.NET6實作聊天室(實時聊天SignalR)

前端通過,signalR内置方法 .invoke()  去請求接口

(附源碼)vue3.0+.NET6實作聊天室(實時聊天SignalR)

3、監聽接受方法(渲染消息)

通過 new signalR.HubConnectionBuilder().on("接受方法") 這個函數

然後将接受的消息 存放到數組裡 

(附源碼)vue3.0+.NET6實作聊天室(實時聊天SignalR)

 再 v-for 将資料渲染出來

(附源碼)vue3.0+.NET6實作聊天室(實時聊天SignalR)

4、退出浏覽器或登出,觸發 “連接配接終止時調用” (OnDisconnectedAsync)

修改登入狀态為 離線

/// <summary>
        /// 連接配接終止時調用。
        /// </summary>
        /// <returns></returns>
        public override Task OnDisconnectedAsync(Exception? exception)
        {
            var httpContext = Context.GetHttpContext();
            var username = httpContext.Request.Cookies["username"];

            if (username == null)
            {
                throw new Exception("系統異常連接配接失敗");
            }

            // 修改使用者登入狀态
            _ChatLoginService.Update(s => s.ChatUserName == username,
               f => new ChatUser
               {
                   Status = 0
               });

            var user = clientusers.Where(p => p.ConnectionId == Context.ConnectionId).FirstOrDefault();
            判斷使用者是否存在,否則添加集合
            if (user != null)
            {
                clientusers.Remove(user);
            }
            return base.OnDisconnectedAsync(exception);
        }
           

在檔案夾 ARW-vue-main\src\views\tool\chat 中的 index.vue 是簡易版的demo

(附源碼)vue3.0+.NET6實作聊天室(實時聊天SignalR)

可以先把這個搞明白,後面會很好了解

這個對應的Hub 是 MessageHub 

(附源碼)vue3.0+.NET6實作聊天室(實時聊天SignalR)

二. Hub模型的方法介紹

繼承成Hub類,是以可以Override三個方法:

  (1). OnConnected:連接配接成功時調用

  (2). OnDisconnected:連接配接斷開時調用

  (3). OnReconnected:重連時調用

我這裡用于 修改使用者登入狀态 線上人數清單...

使用Clients對象進行調用,Clients對象下的屬性和方法有:

(1). 向指定人發送,一對一:Client(string connectionId)

(2). 向某個組發送:Group(roomName)

(3). 進入某個房間:Group.AddToGroupAsync(connectId, roomName)

三. 伺服器端代碼介紹

        好友聊天思路詳細講解:

/// <summary>
        /// 好友發送資訊
        /// </summary>
        /// <param name="user"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public async Task SendFriendsChat(string selfConnectionId, string connectId, string sender, string receiver, string message)
        {
            if (string.IsNullOrEmpty(connectId))
            {
                throw new CustomException("好友不線上,請留言!");
            }

            // 服務端主動調用用戶端的方法
            // 向指定使用者(connectId)發送指定消息
            // 監聽接受方法("ReceiveMessage")來擷取消息 -> ( new { sender, receiver, message } )
            await Clients.Client(connectId).SendAsync("ReceiveMessage", new { sender, receiver, message });
            await Clients.Client(selfConnectionId).SendAsync("ReceiveMessage", new { sender, receiver, message });
        }
           

我們直接手撕源碼,先看這個方法的參數 一共有5個

參數說明: connectId-> 在連接配接SignalR時會給該使用者生成一個連接配接Id,并存在線上使用者清單裡

後面統稱 "連接配接ID"

1、selfConnectionId -> 自己的連接配接ID

2、connectId -> 對方的連接配接ID

3、sender -> 發送者的使用者GUID

4、receiver-> 接收者的使用者GUID

5、message -> 發送的消息

首先我們給發送消息,必須先知道對方的 connectId

才能夠調用 Clients.Client(connectId).SendAsync(.......)

Q:為什麼需要自己的連接配接ID呢?

A:因為給對方發送,對方能夠接收到消息,但自己是接收不到的,是以這裡要給自己也發一份。因而需要傳自己的連接配接ID。

Q:如何區分是誰發送的消息?

A:這裡我用的是 接收者 和 發送者 做的判斷,這裡需要捋一捋思路,是以這裡要傳發送者的GuId 和 接收者的GuId。(發送消息時也帶 sender 和 recevier)

(附源碼)vue3.0+.NET6實作聊天室(實時聊天SignalR)
 下圖是我在渲染聊天清單時做的判斷:
(附源碼)vue3.0+.NET6實作聊天室(實時聊天SignalR)

Q:如果好友不線上,擷取不到對方的連接配接ID怎麼辦?

A:這個情況再去請求Hub接口是會報錯的,因為對方的連接配接Id是空的。我的做法是每次發送一條消息就會存進資料庫裡嘛,然後判斷一下對方是否線上,不線上就擷取他們之間的對話的最新一條消息,這裡sql比較複雜,感興趣的可以看看這個。

看懂這個方法後,來看一下 前端調用

基礎使用

對前端感興趣的可以看一下源碼

        群聊聊天思路詳解:

/// <summary>
        /// 進入指定組
        /// </summary>
        /// <param name="connectId"></param>
        /// <param name="roomName">組的名稱</param>
        [HubMethodName(nameof(EnterRoom))]
        public void EnterRoom(string connectId, string roomName)
        {
            Groups.AddToGroupAsync(connectId, roomName);
        }

        /// <summary>
        /// 群聊天(發送資訊)
        /// </summary>
        /// <param name="roomName"></param>
        public async Task SendGroupChat(string roomName, string groupGuId, string selfConnectionId, string senderId, string receiver, string message)
        {
            var guid = senderId.ParseToLong();
            var groupguid = groupGuId.ParseToLong();
            var sender = _ChatLoginService.FindUserByGuid(guid).Result;

            await Clients.Group(roomName)
                .SendAsync("groupMessages", new { roomName, sender, receiver, message });

            _GroupUserService.Update(s => s.GroupGuId == groupguid,
            f => new GroupUser
            {
                IsRead = false
            });

            //await Clients.Client(selfConnectionId).SendAsync("groupMessages", new { sender, receiver, message });
        }

    }
           

我們繼續手撕源碼,先看這個方法的參數 一共有6個

參數說明: roomName -> 在SignalR中組名,如果沒有這個組名則添加并進入清單,有則加入組

後面統稱 "組"

1、roomName -> 組名

2、groupGuId -> 群聊的GUID

3、selfConnectionId -> 自己的連接配接ID

4、senderId -> 發送者的使用者GUID

5、receiver-> 接收者的GUID(這裡指群聊的GUID)

6、message -> 發送的消息

Clients.Group(roomName).SendAsync("接受方法名",發送的消息)
           

首先要 進入到房間内:

把自己的連接配接ID放進去,以及群聊名稱

Groups.AddToGroupAsync(connectId, roomName);
           

在群聊發送消息,需要做到:

1、通過 roomName 發送消息到這個房間

2、通過 groupGuId 來修改使用者是否已讀

3、通過 senderId 來判斷是否自己發的,不是則展示群成員發的頭像和所發的消息

4、通過 receiver 來判斷這個群聊是否為指定的群

(附源碼)vue3.0+.NET6實作聊天室(實時聊天SignalR)