1、概述
通过前面几篇文章对SignalR的详细介绍。我们知道Asp.net SignalR是微软为实现实时通信的一个类库。一般情况下,SignalR会使用JavaScript的长轮询(long polling)的方式来实现客户端和服务器通信,随着Html5中WebSockets出现,SignalR也支持WebSockets通信。另外SignalR开发的程序不仅仅限制于宿主在IIS中,也可以宿主在任何应用程序,包括控制台,客户端程序和Windows服务等,另外还支持Mono,这意味着它可以实现跨平台部署在Linux环境下。
SignalR内部有两类对象:
Http持久连接(Persisten Connection)对象:用来解决长时间连接的功能。还可以由客户端主动向服务器要求数据,而服务器端不需要实现太多细节,只需要处理PersistentConnection 内所提供的五个事件:OnConnected, OnReconnected, OnReceived, OnError 和 OnDisconnect 即可。
Hub(集线器)对象:用来解决实时(realtime)信息交换的功能,服务端可以利用URL来注册一个或多个Hub,只要连接到这个Hub,就能与所有的客户端共享发送到服务器上的信息,同时服务端可以调用客户端的脚本。
SignalR将整个信息的交换封装起来,客户端和服务器都是使用JSON来沟通的,在服务端声明的所有Hub信息,都会生成JavaScript输出到客户端,.NET则依赖Proxy来生成代理对象,而Proxy的内部则是将JSON转换成对象。
2、SignalR实现聊天室(群聊)功能
要想实现群聊的功能,首先我们需要创建一个房间,然后每个在线用户可以加入这个房间里面进行群聊,我们可以为房间设置一个唯一的名字来作为标识。那SignalR类库里面是否有这样现有的方法呢?答案是肯定的。SignalR作为一个强大的集线器,已经在hub里面集成了Gorups,也就是分组管理。
// IGroupManager接口提供如下方法
// 作用:将连接ID加入某个组
// Context.ConnectionId 连接ID,每个页面连接集线器即会产生唯一ID
// roomName分组的名称
Groups.Add(Context.ConnectionId, roomName);
// 作用:将连接ID从某个分组移除
Groups.Remove(Context.ConnectionId, roomName);
// IHubConnectionContext接口提供了如下方法
// 调用客户端方法向房间内所有用户群发消息
// Room:分组名称
// new string[0]:过滤(不发送)的连接ID数组
Clients.Group(Room, new string[0]).clientMethod
上面的代码就是实现群聊的核心方法。Groups对象就是SignalR类库维护的一个列表对象而已,我们完全可以自己维护一个Dictionary
2.1、 创建ASP.NET Mvc项目
新建一个空的ASP.NET Mvc项目,取名为:SignalRGroupChat。
2.2、安装Nuget包
创建好项目后,要使用SignalR,需要先安装SignalR包,可以通过程序包管理控制台输入包安装命令进行安装。
Install-Package Microsoft.AspNet.SignalR
Install-Package Microsoft.Owin.Cors
2.3、聊天室后台代码实现
要实现聊天室功能,我们需要一些基础实体,如:用户类、房间类等,直接上代码:
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace SignalRGroupChat
{
public class UserContext
{
public UserContext()
{
Users = new List();
Connections = new List();
Rooms = new List();
}
///
/// 用户集合
///
public List Users { get; set; }
///
/// 连接集合
///
public List Connections { get; set; }
///
/// 房间集合
///
public List Rooms { get; set; }
}
public class User
{
///
/// 用户名
///
[Key]
public string UserName { get; set; }
///
/// 用户的连接
///
public List Connections { get; set; }
///
/// 用户房间集合
///
public virtual List Rooms { get; set; }
public User()
{
Connections = new List();
Rooms = new List();
}
}
public class Connection
{
///
/// 连接ID
///
public string ConnectionID { get; set; }
///
/// 用户代理
///
public string UserAgent { get; set; }
///
/// 是否连接
///
public bool Connected { get; set; }
}
///
/// 房间类
///
public class ConversationRoom
{
///
/// 房间名称
///
[Key]
public string RoomName { get; set; }
///
/// 用户集合
///
public virtual List Users { get; set; }
public ConversationRoom()
{
Users = new List();
}
}
}
实现聊天室的SignalR Hub代码:
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using Newtonsoft.Json;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace SignalRGroupChat.Hubs
{
///
/// 聊天室(群聊)
///
[HubName("groupHub")]
public class GroupHub : Hub
{
public static UserContext db = new UserContext();
public void Hello()
{
Clients.All.hello();
}
///
/// 重写Hub连接事件
///
///
public override Task OnConnected()
{
// 查询用户。
var user = db.Users.SingleOrDefault(u => u.UserName == Context.ConnectionId);
//判断用户是否存在,否则添加
if (user == null)
{
user = new User()
{
UserName = Context.ConnectionId
};
db.Users.Add(user);
}
//发送房间列表
var itme = from a in db.Rooms
select new { a.RoomName };
Clients.Client(this.Context.ConnectionId).getRoomlist(JsonConvert.SerializeObject(itme.ToList()));
return base.OnConnected();
}
///
/// 更新所有用户的房间列表
///
private void GetRoomList()
{
var itme = from a in db.Rooms
select new { a.RoomName };
string jsondata = JsonConvert.SerializeObject(itme.ToList());
Clients.All.getRoomlist(jsondata);
}
// 重写Hub连接断开的事件
public override Task OnDisconnected(bool stopCalled)
{
// 查询用户
var user = db.Users.FirstOrDefault(u => u.UserName == Context.ConnectionId);
if (user != null)
{
// 删除用户
db.Users.Remove(user);
// 从房间中移除用户
foreach (var item in user.Rooms)
{
RemoveFromRoom(item.RoomName);
}
}
return base.OnDisconnected(stopCalled);
}
///
/// 加入聊天室
///
///
public void AddToRoom(string roomName)
{
//查询聊天室
var room = db.Rooms.Find(a => a.RoomName == roomName);
//存在则加入
if (room != null)
{
//查找房间中是否存在此用户
var isuser = room.Users.Where(a => a.UserName == Context.ConnectionId).FirstOrDefault();
//不存在则加入
if (isuser == null)
{
var user = db.Users.Find(a => a.UserName == Context.ConnectionId);
user.Rooms.Add(room);
room.Users.Add(user);
Groups.Add(Context.ConnectionId, roomName);
//调用此连接用户的本地JS(显示房间)
Clients.Client(Context.ConnectionId).addRoom(roomName);
}
else
{
Clients.Client(Context.ConnectionId).showMessage("请勿重复加入房间!");
}
}
}
///
/// 创建聊天室
///
///
public void CreatRoom(string roomName)
{
var room = db.Rooms.Find(a => a.RoomName == roomName);
if (room == null)
{
ConversationRoom cr = new ConversationRoom()
{
RoomName = roomName
};
//将房间加入列表
db.Rooms.Add(cr);
AddToRoom(roomName);
Clients.Client(Context.ConnectionId).showMessage("房间创建完成!");
GetRoomList();
}
else
{
Clients.Client(Context.ConnectionId).showMessage("房间名重复!");
}
}
///
/// 退出聊天室
///
///
public void RemoveFromRoom(string roomName)
{
//查找房间是否存在
var room = db.Rooms.Find(a => a.RoomName == roomName);
//存在则进入删除
if (room != null)
{
//查找要删除的用户
var user = room.Users.Where(a => a.UserName == Context.ConnectionId).FirstOrDefault();
//移除此用户
room.Users.Remove(user);
//如果房间人数为0,则删除房间
if (room.Users.Count <= 0)
{
db.Rooms.Remove(room);
}
Groups.Remove(Context.ConnectionId, roomName);
//提示客户端
Clients.Client(Context.ConnectionId).removeRoom("退出成功!");
}
}
///
/// 给分组内所有的用户发送消息
///
/// 分组名
/// 信息
public void SendMessage(string Room, string Message)
{
Clients.Group(Room, new string[0]).sendMessage(Room, Message + " " + DateTime.Now.ToString("HH:mm:ss"));
}
}
}
2.4、页面部分代码参考
@{
ViewBag.Title = "GroupChat";
}
聊天室(群聊)实例
当前用户:
输入房间名:
房间列表
@section scripts {
}
3、效果展示
4、代码下载
实例源码可以移步github下载,地址:https://github.com/yonghu86/SignalRTestProj
5、参考文章
RDIFramework.NET敏捷开发框架通过SignalR技术整合即时通讯(IM)
史上最全面的SignalR系列教程-1、认识SignalR
史上最全面的SignalR系列教程-2、SignalR 实现推送功能-永久连接类实现方式
史上最全面的SignalR系列教程-3、SignalR 实现推送功能-集线器类实现方式
史上最全面的SignalR系列教程-4、SignalR 自托管全解(使用Self-Host)-附各终端详细实例
史上最全面的SignalR系列教程-5、SignalR 实现一对一聊天
Real-time ASP.NET with SignalR
微信公众号开发系列-玩转微信开发-目录汇总
RDIFramework.NET — 基于.NET的快速信息化系统开发框架 — 系列目录
RDIFramework.NET ━ .NET快速信息化系统开发框架 ━ 工作流程组件介绍
RDIFramework.NET框架SOA解决方案(集Windows服务、WinForm形式与IIS形式发布)-分布式应用
RDIFramework.NET代码生成器全新V3.5版本发布-重大升级
一路走来数个年头,感谢RDIFramework.NET框架的支持者与使用者,大家可以通过下面的地址了解详情。
RDIFramework.NET官方网站:http://www.rdiframework.net/
RDIFramework.NET官方博客:http://blog.rdiframework.net/
同时需要说明的,以后的所有技术文章以官方网站为准,欢迎大家收藏!
RDIFramework.NET框架由海南国思软件科技有限公司专业团队长期打造、一直在更新、一直在升级,请放心使用!
欢迎关注RDIFramework.net框架官方公众微信(微信号:guosisoft),及时了解最新动态。
扫描二维码立即关注