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. 企业如何从“API优先”的策略中获益

    在过去的几年里,全球API经济在以难以置信的速度进行快速地增长.物联网.人工智能.自动驾驶等等众多令人充满期待的技术正蓬勃发展,这也证明了API对于如今整个技术圈子的重要性,也预示着在不久的将来它还将 ...

  2. 自定义SSL证书实现单双向ssl认证记录

    自定义SSL证书: 1.ca证书 #openssl genrsa -out ca.key 2048 #openssl req -new -key ca.key -out ca.csr #openssl ...

  3. 洛谷P2598 [ZJOI2009]狼和羊的故事 题解

    题目链接: https://www.luogu.org/problemnew/show/P2598 分析: 我们知道此题的目的是将狼和羊分割开,很容易想到狼在S,羊在T中. 首先,我们可以在狼,羊,空 ...

  4. 个人永久性免费-Excel催化剂功能第56波-获取Excel对象属性相关自定义函数

    之前零散开发过一些自定义函数获取Excel对象属性,此次再细细地把有价值的属性都一一给开发完成,某些场景下,有这些小函数还是可以比较方便地实现一些通过Excel界面没法轻松获取到的信息. 修复与更新 ...

  5. 机器学习-利用pickle加载cifar文件

    首先这里有百度云的数据集供大家下载:(官网太慢了) 链接:https://pan.baidu.com/s/1G0MxZIGSK_DyZTcuNbxraQ 提取码:ui51 复制这段内容后打开百度网盘手 ...

  6. [剑指offer] 46. 孩子们的游戏(圆圈中最后剩下的数)

    题目描述 随机指定一个数m,让编号为0的小朋友开始报数.每次喊到m-1的那个小朋友要出列,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友 ...

  7. 基站搭建与IMSI捕获

     写在前面 : 实验目的是为了教学交流,坚决抵制违法行为. 一.实验目的 搭建基于OpenBTS的基站,手机接入该基站,进行短信.语音等测试. 二.所用仪器 USRP B210 1台,天线2根,PC机 ...

  8. C#学习书单

    [入门] (1)<C#入门经典> (2)<牛腩新闻发布系统> [深入] (1)<CLR via C#(第4版)> (2)<深入理解C#(第3版)> [C ...

  9. 转 java - java基础知识点

    转 https://www.cnblogs.com/xdp-gacl/p/3641769.html 1.一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 可 ...

  10. 【Java】You have an error in your SQL syntax ...

    详情如下: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server v ...