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,如下图所示。为了整个系列的完整性,我们直接在上一项目的基础上新增的一个测试项目,后面有项目的源码托管地址。

2.2、安装Nuget包

创建好项目后,要使用SignalR,需要先安装SignalR包,可以通过程序包管理控制台输入包安装命令进行安装。

Install-Package Microsoft.AspNet.SignalR

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

2.3、一对一聊天后台代码实现###

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

实现的主要步骤:

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

可以看到我们服务端开发的两个方法,需要特别说明的是服务器端的方法名在客户端调用都约定第一个字母为小写,当然我们也可以通过方法名上加特性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),及时了解最新动态。

扫描二维码立即关注

史上最全面的SignalR系列教程-5、SignalR 实现一对一聊天的更多相关文章

  1. 史上最全面的SignalR系列教程-2、SignalR 实现推送功能-永久连接类实现方式

    1.概述 通过上篇史上最全面的SignalR系列教程-1.认识SignalR文章的介绍,我们对SignalR技术已经有了一个全面的了解.本篇开始就通过SignalR的典型应用的实现方式做介绍,例子虽然 ...

  2. 史上最全面的SignalR系列教程-3、SignalR 实现推送功能-集线器类实现方式

    1.概述 通过前两篇 史上最全面的SignalR系列教程-1.认识SignalR 史上最全面的SignalR系列教程-2.SignalR 实现推送功能-永久连接类实现方式 文章对SignalR的介绍, ...

  3. 史上最全面的SignalR系列教程-4、SignalR 自托管全解(使用Self-Host)-附各终端详细实例

    1.概述 通过前面几篇文章 史上最全面的SignalR系列教程-1.认识SignalR 史上最全面的SignalR系列教程-2.SignalR 实现推送功能-永久连接类实现方式 史上最全面的Signa ...

  4. 史上最全面的SignalR系列教程-6、SignalR 实现聊天室

    1.概述 通过前面几篇文章对SignalR的详细介绍.我们知道Asp.net SignalR是微软为实现实时通信的一个类库.一般情况下,SignalR会使用JavaScript的长轮询(long po ...

  5. 史上最全面的SignalR系列教程-目录汇总

    1.引言 最遗憾的不是把理想丢在路上,而是理想从未上路. 每一个将想法变成现实的人,都值得称赞和学习. 致正在奔跑的您! 2.SignalR介绍 SignalR实现服务器与客户端的实时通信 ,她是一个 ...

  6. .Net魔法堂:史上最全的ActiveX开发教程——ActiveX与JS间交互篇

    一.前言 经过上几篇的学习,现在我们已经掌握了ActiveX的整个开发过程,但要发挥ActiveX的真正威力,必须依靠JS.下面一起来学习吧! 二.JS调用ActiveX方法 只需在UserContr ...

  7. .Net魔法堂:史上最全的ActiveX开发教程——开发篇

    一.前言 在设计某移动内部自动化运维平台时,经综合考虑终端机性能和功能需求等因素后,决定采用B/S模式,并且浏览器通过ActiveX组件实现与服务器Agent作P2P的通讯.好处,整个平台以网页形式存 ...

  8. .Net魔法堂:史上最全的ActiveX开发教程——自动更新、卸载篇

    一.前言 B/S模式的特点之一,客户端版本升级相对简单.快捷,适合产品的快速迭代.而ActiveX组件的自动更新同样也继承了这一优点.下面我们一起来了解吧! 二.二话不说更新ActiveX 1. 设置 ...

  9. .Net魔法堂:史上最全的ActiveX开发教程——部署篇

    一.前言 接<.Net魔法堂:史上最全的ActiveX开发教程——发布篇>,后我们继续来部署吧! 二. 挽起衣袖来部署   ActiveX的部署其实就是客户端安装ActiveX组件,对未签 ...

随机推荐

  1. Spring Aware 到底是什么?

    通过如下前序两篇文章: Spring Bean 生命周期之"我从哪里来"? Spring Bean 生命周期之"我要到哪里去"? 我们了解了 Spring Be ...

  2. 从零开始认识Dubbo

    目录 1.Dubbo是什么 2.Dubbo能做什么 3.Dubbo架构 4.Dubbo的使用方法 5.使用Dubbo可能遇到的问题 1.Dubbo是什么 http://dubbo.apache.org ...

  3. 【朝花夕拾】Android自定义View篇之(十一)View的滑动,弹性滑动与自定义PagerView

    前言 由于手机屏幕尺寸有限,但是又经常需要在屏幕中显示大量的内容,这就使得必须有部分内容显示,部分内容隐藏.这就需要用一个Android中很重要的概念——滑动.滑动,顾名思义就是view从一个地方移动 ...

  4. 使用flink Table &Sql api来构建批量和流式应用(3)Flink Sql 使用

    从flink的官方文档,我们知道flink的编程模型分为四层,sql层是最高层的api,Table api是中间层,DataStream/DataSet Api 是核心,stateful Stream ...

  5. SVG波浪动画

    今天来试试用svg+css3制作波浪动画 下图是我制作出的效果 还不错吧 在制作波浪前,首先我们要画波浪啊,至于画波浪,如果你想直接通过计算贝塞尔曲线绘制出波浪... 好吧,那我也不拦着你 我就直接用 ...

  6. 个人永久性免费-Excel催化剂功能第101波-批量替换功能(增加正则及高性能替换能力)

    数据处理无小事,正如没有人活在真空理想环境一下,在数据分析过程中,也没有那么真空理想化的数据源可以使用,数据处理占据数据分析的80%的时间,每一个小小的改善,获益都良多.Excel查找替换,有其局限性 ...

  7. 关于Object.defineProperty 的基础知识

    Object.defineProperty 这个方法大家耳熟能详,可以对 对象的属性进行添加或修改的操作.即可以进行  数据劫持 .vue就是通过这个方法来劫持数据的. 平时我们创建对象的时候,一般通 ...

  8. GCC 编译多个文件

    今天写数据结构的example,定义了3个文件:lish.h list.c main.c list.h是list.c的头文件,mian.c中对list.h进行了引用.代码如下: list.h 1 #i ...

  9. 记一次搭建ftp服务器的简略经历

    需求:在linux中搭建一个ftp 服务器,用户为:user1 目录为 /data/use1  ,          安全设置:限制权限,只能访问自己目录,限制端口,只允许特定ip访问. 1,安装vs ...

  10. IO-文件输出流

    一.输出流的原理 Java向文件中写数据的原理 Java程序-->JVM(java虚拟机)-->OS(操作系统)-->OS调用写数据的方法-->把数据写入到文件中 tips: ...