史上最全面的SignalR系列教程-5、SignalR 实现一对一聊天

998 阅读6分钟

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给我们生成的方法:

F12Hubs代码效果

可以看到我们服务端开发的两个方法,需要特别说明的是服务器端的方法名在客户端调用都约定第一个字母为小写,当然我们也可以通过方法名上加特性HubMethodName进行标识处理。

4、代码下载

实例源码可以移步github下载,地址:github.com/yonghu86/Si…

5、参考文章


一路走来数个年头,感谢RDIFramework.NET框架的支持者与使用者,大家可以通过下面的地址了解详情。

RDIFramework.NET官方网站:www.rdiframework.net/

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

同时需要说明的,以后的所有技术文章以官方网站为准,欢迎大家收藏!

RDIFramework.NET框架由海南国思软件科技有限公司专业团队长期打造、一直在更新、一直在升级,请放心使用!

欢迎关注RDIFramework.net框架官方公众微信(微信号:guosisoft),及时了解最新动态。

扫描二维码立即关注

微信号:guosisoft