史上最全面的SignalR系列教程-5、SignalR 實現一對一聊天

1、概述

通過前面幾篇文章

史上最全面的SignalR系列教程-1、認識SignalR

史上最全面的SignalR系列教程-2、SignalR 實現推送功能-永久連接類實現方式

史上最全面的SignalR系列教程-3、SignalR 實現推送功能-集線器類實現方式

史上最全面的SignalR系列教程-4、SignalR 自託管全解(使用Self-Host)-附各終端詳細實例

RDIFramework.NET敏捷開發框架通過SignalR技術整合即時通訊(IM)

我們對SignalR算入門了,知道如何把SignalR合理應用到實際的項目中。前面的文章主要講解的是SignalR的概念,託管方式,以及推送的功能。本篇主要講解通過SignalR實現一對一、點對點的聊天。

2、SignalR一對一聊天實現

2.1、 創建ASP.NET Mvc項目

新建一個空的ASP.NET Mvc項目,取名爲:SignalROneToOne,如下圖所示。爲了整個系列的完整性,我們直接在上一項目的基礎上新增的一個測試項目,後面有項目的源碼託管地址。

新建SignalROneToOne測試項目

2.2、安裝Nuget包

創建好項目後,要使用SignalR,需要先安裝SignalR包,可以通過程序包管理控制檯輸入包安裝命令進行安裝。

Install-Package Microsoft.AspNet.SignalR

也可以使用界面方式,如下圖所示。

安裝SignalR包-Microsoft.AspNet.SignalR

2.3、一對一聊天后臺代碼實現###

向工程中添加HubConnections目錄,在其中添加OneToOneHub.cs文件,如下圖所示:

添加OneToOneHub

實現的主要步驟:

  1. 重寫OnConnected連接方法和OnDisconnected斷開方法。
  2. 使用SendMessage服務器端方法發送消息,GetName獲取用戶名。
  3. 客戶端響應的提示返回信息方法,如Clients.Client(Context.ConnectionId).addMessage(message)

OneToOneHub代碼內容如下:

using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace SignalROneToOneDemo.Connections
{
    /// <summary>
    /// 用戶實體類
    /// </summary>
    public class User
    {
        /// <summary>
        /// 連接ID
        /// </summary>
        [Key]
        public string ConnectionID { get; set; }

        /// <summary>
        /// 用戶名稱
        /// </summary>
        public string Name { get; set; }

        public User(string name, string connectionId)
        {
            this.Name = name;
            this.ConnectionID = connectionId;
        }
    }

    /// <summary>
    /// 點對點(一對一)聊天
    /// </summary>
    [HubName("chat")]
    public class OneToOneHub : Hub
    {
        public static List<User> users = new List<User>();

        //發送消息
        public void SendMessage(string connectionId, string message)
        {
            Clients.All.hello();
            var user = users.Where(s => s.ConnectionID == connectionId).FirstOrDefault();
            if (user != null)
            {
                Clients.Client(connectionId).addMessage(message + "" + DateTime.Now, Context.ConnectionId);
                //給自己發送,把用戶的ID傳給自己
                Clients.Client(Context.ConnectionId).addMessage(message + "" + DateTime.Now, connectionId);
            }
            else
            {
                Clients.Client(Context.ConnectionId).showMessage("該用戶已離線...");
            }
        }

        [HubMethodName("getName")]
        public void GetName(string name)
        {
            //查詢用戶
            var user = users.SingleOrDefault(u => u.ConnectionID == Context.ConnectionId);
            if (user != null)
            {
                user.Name = name;
                Clients.Client(Context.ConnectionId).showId(Context.ConnectionId);
            }
            GetUsers();
        }

        /// <summary>
        /// 重寫連接事件
        /// </summary>
        /// <returns></returns>
        public override Task OnConnected()
        {
            //查詢用戶
            var user = users.Where(u => u.ConnectionID == Context.ConnectionId).SingleOrDefault();
            //判斷用戶是否存在,否則添加集合
            if (user == null)
            {
                user = new User("", Context.ConnectionId);
                users.Add(user);
            }
            return base.OnConnected();
        }

        public override Task OnDisconnected(bool stopCalled)
        {
            var user = users.Where(p => p.ConnectionID == Context.ConnectionId).FirstOrDefault();
            //判斷用戶是否存在,存在則刪除
            if (user != null)
            {
                //刪除用戶
                users.Remove(user);
            }
            GetUsers();//獲取所有用戶的列表
            return base.OnDisconnected(stopCalled);
        }

        //獲取所有用戶在線列表
        private void GetUsers()
        {
            var list = users.Select(s => new { s.Name, s.ConnectionID }).ToList();
            string jsonList = JsonConvert.SerializeObject(list);
            Clients.All.getUsers(jsonList);
        }
    }
}

如果你是vs2015 的話添加的mvc項目 不進行身份驗證的那種吧,必須得添加一個Startup 類。如果沒有這個類請添加,不然的話項目運行不起來的,具體代碼如下:

using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(SignalROneToOneDemo.App_Start.SignalRQuickStart))]

namespace SignalROneToOneDemo.App_Start
{
    public class SignalRQuickStart
    {
        public void Configuration(IAppBuilder app)
        {
            // 有關如何配置應用程序的詳細信息,請訪問 https://go.microsoft.com/fwlink/?LinkID=316888
            // 配置集線器
            app.MapSignalR();
        }
    }
}

2.4、一對一聊天前臺代碼實現###

@{
    ViewBag.Title = "OneToOneChat";
}

<h2>點對點(一對一)聊天實例代碼</h2>

<div>
    <div>用戶名稱:<label id="userName"></label>(<label id="conId"></label>)</div>
    
    <div style="width:25%;border:1px solid #ff0000">
        <div>在線用戶列表</div>
        <ul id="users"></ul>
    </div>
    <div id="userBox">
    </div>
</div>

@section scripts {
    <script src="~/Scripts/jquery-3.3.1.min.js"></script>
    <script src="~/Scripts/jquery.signalR-2.4.1.min.js"></script>
    <script src="~/signalr/hubs"></script>
    <script type="text/javascript">
        var clients = [];
        var chat;
        $(function () {        
            chat = $.connection.chat;
            console.info(chat);

            //顯示提示方法
            chat.client.showMessage = function (message) {
                alert(message);
            }

            //註冊顯示信息的方法
            chat.client.addMessage = function (message, connectionId) {
                //debugger
                if ($.inArray(connectionId, clients)==-1) {
                    showWin(connectionId);
                }
      
                $("#messages" + connectionId).each(function () {
                    $(this).append('<li>'+message+'</li>');
                })
            }

            //註冊顯示所有用戶的方法
            chat.client.getUsers = function (data) {            
                if (data) {
                    var json = $.parseJSON(data);                    
                    console.info(json);
                    $("#users").html(" ");
                    for (var i = 0; i < json.length; i++) {                        
                        var html = '<li>用戶名:' + json[i].Name + '<input type="button" connectionId="' + json[i].ConnectionID + '" id="'  + json[i].ConnectionID + '" value="聊天"  onclick="userChat(this)" />' ;
                        $("#users").append(html);
                    }
                }
            }

            //註冊顯示推出聊天提示的方法
            chat.client.exitUser = function (data)
            {
                alert(data);
            }

            //註冊顯示個人信息的方法
            chat.client.showId = function (data)
            {
                $("#conId").html(data);
                clients.push(data);
            }

            //獲取用戶名稱
            $('#userName').html(prompt('請輸入您的名稱', ''));
 
            //連接成功後獲取自己的信息
            $.connection.hub.start().done(function () {
                chat.server.getName($('#userName').html());
            });
        });

        //開始聊天
        function userChat(obj)
        {
            var connectionId = $(obj).attr('connectionId');
            showWin(connectionId);
        }

        function showWin(connectionId)
        { 
            clients.push(connectionId);
            var html = '<div style="float:left;margin-top:5px;margin-right: 5px;margin-bottom: 5px;border:1px solid #ff0000" id="' + connectionId + '" connectionId="' + connectionId + '">' + connectionId + '"的房間聊天記錄如下:<button onclick="exitChat(this)">退出</button><ul id="messages' + connectionId + '"></ul><input type="text" /> <button onclick="sendMessage(this)">發送</button></div>';
            $("#userBox").append(html);
        }

        function exitChat(btnObj)
        {          
            $(btnObj).parent().remove();
            chat.server.exitChat(connectionId);
        }

        //發送消息
        function sendMessage(data)
        {
            var message = $(data).prev().val();
            var  userObj = $(data).parent();
            var username = $("#userName").html();
            message = username + ":" + message;
            console.info($(userObj).attr("connectionId"));
            var targetConnectionId = $(userObj).attr("connectionId");
            chat.server.sendMessage(targetConnectionId, message);
            $(data).prev().val("");
        }
    </script>
}

3、效果展示

一對一聊天效果展示

到此,一個SignalR一對一(點對點)聊天例子就完成了,下面我們簡單的對代碼作下分析:

Clients.Client(connectionId).addMessage():作用客戶端註冊addMessage方法,向指定連接Id的客戶端發送消息。由於一對一聊天發送的消息也應該回發給自己,所以回發給自己連接的Id可以通過Context.ConnectionId來獲取。當然也也可以使用Client.Caller()代替Client.Client(Context.ConnectionId)方法直接發送。

Client.Clients(IList connectionIds):同時向多個ConnectionId發送消息,類似於QQ上@好友的功能。

通過瀏覽器F12我們可以看到SignalR給我們生成的方法:

[外鏈圖片轉存失敗(img-GYymAggz-1566444208515)(http://doc.rdiframework.net/blog/article/20190822111606097.png-pw)]

可以看到我們服務端開發的兩個方法,需要特別說明的是服務器端的方法名在客戶端調用都約定第一個字母爲小寫,當然我們也可以通過方法名上加特性HubMethodName進行標識處理。

4、代碼下載

實例源碼可以移步github下載,地址:https://github.com/yonghu86/SignalRTestProj

5、參考文章


一路走來數個年頭,感謝RDIFramework.NET框架的支持者與使用者,大家可以通過下面的地址瞭解詳情。

RDIFramework.NET官方網站:http://www.rdiframework.net/

RDIFramework.NET官方博客:http://blog.rdiframework.net/

同時需要說明的,以後的所有技術文章以官方網站爲準,歡迎大家收藏!

RDIFramework.NET框架由海南國思軟件科技有限公司專業團隊長期打造、一直在更新、一直在升級,請放心使用!

歡迎關注RDIFramework.net框架官方公衆微信(微信號:guosisoft),及時瞭解最新動態。

掃描二維碼立即關注

微信號:guosisoft

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章