原文:
使用ASP.NET SignalR实现一个简单的聊天室
前言
距离我写上一篇博客已经又过了一年半载了,时间过得很快,一眨眼,就把人变得沧桑了许多。青春是短暂的,知识是无限的。要用短暂的青春,去学无穷无尽的知识,及时当勉励,岁月不待人。今天写个随笔小结记录一下。
什么是SignalR?
陌生的关键字,百度科普一下,什么是SignalR?ASP .NET SignalR 是一个ASP .NET 下的类库,可以在web中实现实时通信。服务器端可以将消息自动推送到已连接的客户端。官方网站SignalR介绍写得很详细, http://www.asp.net/signalr/overview/getting-started/tutorial-getting-started-with-signalr 官网是英文的,如果像我一样看英文看的头疼的,可以像我一样试试把url中的 “en-us”改为 “zh-cn” 刷新即变成中文的了,

先看几个我做的效果图



这个聊天室,刚开始前端我用的是BootStrap,Css和页面布局我是拷贝了网上的别人改过的,直接搬过来用的,具体是哪里找的忘记了。。 QAQ。在此谢过了。聊天室中我实现了登录,公共聊天,组件群聊,私聊,消息推送,保存聊天记录等等功能。后来基本功能实现了后,前端我使用vue.js+webapi前后端分离了。
新建项目,SignalR入门
1)新建一个asp.net web项目,类型为MVC,取名为SignalRChat,然后在引用中添加NuGet浏览中安装SignalR。或者在工具栏中,程序包管理控制台输入如下语句安装SignalR:install-package Microsoft.AspNet.SignalR
2) 添加hub文件
项目右键新建文件一个文件夹取名为Hubs,在该文件夹下新建一个Signalr集线类(v2),ChatHub类得上面自定义HubName,然后在 startup文件里配置hub路径,默认得HubName是该类名称开头字母小写
3) 建立一个 OWIN Startup 类来配置应用.


1 [assembly: OwinStartup(typeof(SignalRChat.Startup))]
2 namespace SignalRChat
3 {
4 public class Startup
5 {
6 public void Configuration(IAppBuilder app)
7 {
8 app.MapSignalR();
9 }
10 }
11 }
View Code
我的项目结构

Scripts中我只保留了必需用到的几个js,其他不必要的都删除,Model放实体类,common放公共类。SignalRContext类是自定义的一个类,用户保存在线用户的一些连接信息和房间信息等。没有涉及数据库,登陆数据是手动模拟造的数据。
重点在创建的ChatHub集线器中


1 [HubName("chatHub")]
2 public class ChatHub : Hub
3 {
4 #region 全局对象
5 protected static List<UserInfo> userInfoList = new List<UserInfo>();
6 protected static SignalRContext DbContext = new SignalRContext();
7 protected static List<ChatHistory> chatHistoryList = new List<ChatHistory>();
8 #endregion
9
10 #region 连接
11
12 /// <summary>
13 /// 客户端重连接时
14 /// </summary>
15 /// <returns></returns>
16 public override Task OnConnected()
17 {
18 AddUserGroup();//添加用户组
19 UpdateAllRoomList();//更新房间列表
20
21 return base.OnConnected();
22 }
23 /// <summary>
24 /// 断线
25 /// </summary>
26 /// <param name="stopCalled"></param>
27 /// <returns></returns>
28 public override Task OnDisconnected(bool stopCalled)
29 {
30 return base.OnDisconnected(stopCalled);
31 }
32 #endregion
View Code
1)前端引用自动生成得集线器代理对象
var chat = $.connection.chatHub;注意红色标明得注意取 HubName中得名称,如果hubname没注释,就取集线器类中得类名首字母小写。
2) 开始连接服务器
$.connection.hub.start().done(function () { });
公共聊天方法


1 #region 公共聊天
2
3 /// <summary>
4 /// 公共聊天
5 /// </summary>
6 /// <param name="message"></param>
7 /// <param name="name"></param>
8 public void PublicSendMsg(string message, string userId)
9 {
10 var user = userInfoList.FirstOrDefault(x => x.UserID == userId);
11 Clients.All.sendPublicMessage(user.UserID, user.UserName, message);
12 AddChatHistory(ChatType.PubChat,user.UserName, message, user.UserID,"");//添加历史记录
13 }
14 #endregion
View Code
一对一聊天方法


1 /// <summary>
2 /// 发送私聊消息
3 /// </summary>
4 /// <param name="sendName">发送名称</param>
5 /// <param name="userId">用户id</param>
6 /// <param name="message">消息</param>
7 public void SendPrivateMsg(string sendName, string userId, string message)
8 {
9 var toUser = userInfoList.FirstOrDefault(x => x.UserID == userId);//接收用户信息
10 var fromUser = userInfoList.FirstOrDefault(x => x.ConnectionId == Context.ConnectionId);//发送用户信息
11 if (toUser != null && fromUser != null)
12 {
13 Clients.Caller.showMsgToPages(fromUser.UserID, sendName, message);
14 if (fromUser.UserID != userId)//判断是否是自己给自己发消息
15 {
16 Clients.Client(toUser.ConnectionId).remindMsg(fromUser.UserID, fromUser.UserName,message);
17 }
18 AddChatHistory(ChatType.PriChat, sendName, message, fromUser.UserID, userId, "");
19 }
20 }
View Code
多对多聊天,群聊方法


1 /// <summary>
2 /// 创建聊天室
3 /// </summary>
4 /// <param name="roomName"></param>
5 public void CreateRoom(string roomName)
6 {
7 var room = DbContext.Rooms.Find(x => x.RoomName == roomName);
8 if (room == null)
9 {
10 var rom = new ChatRoom
11 {
12 RoomName = roomName,
13 RoomId = Guid.NewGuid().ToString().ToUpper()
14 };
15 DbContext.Rooms.Add(rom);//加入房间列表
16 UpdateAllRoomList();//更新房间列表
17 Clients.Client(Context.ConnectionId).showGroupMsg("success");
18 }
19 else
20 {
21 Clients.Client(Context.ConnectionId).showGroupMsg("error");
22 }
23 }
24
25 /// <summary>
26 ///加入聊天室
27 /// </summary>
28 public void JoinRoom(string roomId,string current_Id)
29 {
30 // 查询聊天室,
31 var room = DbContext.Rooms.Find(x => x.RoomId == roomId.Trim());
32 var u = userInfoList.Find(x => x.UserID == current_Id);
33 if (room != null)
34 {
35 //检测该用户是否存在在该房间
36 var isExistUser = room.Users.Find(x => x.UserConnectionId == Context.ConnectionId);
37 if (isExistUser == null)
38 {
39 var user = DbContext.Users.Find(x => x.UserConnectionId == Context.ConnectionId);
40 user.Rooms.Add(room);//用户信息中加入房间信息
41 room.Users.Add(user);//房间信息中加入用户信息
42 Groups.Add(Context.ConnectionId, room.RoomName);//添加到组中
43 Clients.Group(room.RoomName, new string[0]).showSysGroupMsg(u.UserName);
44 }
45 }
46 else
47 {
48 Clients.Client(Context.ConnectionId).showMessage("该群组不存在");
49 }
50 }
51
52 /// <summary>
53 /// 给指定房间内的所有用户发消息
54 /// </summary>
55 /// <param name="room">房间名</param>
56 /// <param name="message">消息</param>
57 public void SendMessageByRoom(string roomId, string current_Id, string message)
58 {
59 var room = DbContext.Rooms.FirstOrDefault(x=>x.RoomId==roomId);
60 var user = userInfoList.Find(x => x.UserID == current_Id);
61 if (room != null && user != null)
62 {
63 Clients.Group(room.RoomName, new string[0]).showGroupByRoomMsg(user.UserName,room.RoomId, message);
64 AddChatHistory(ChatType.GroChat, user.UserName, message, user.UserID, "", room.RoomId);
65 }
66 }
67
68 /// <summary>
69 /// 退出房间
70 /// </summary>
71 public void RemoveRoom(string roomId)
72 {
73 var room = DbContext.Rooms.Find(x => x.RoomId == roomId);
74 if (room != null)
75 {
76 var user = DbContext.Users.Find(x => x.UserConnectionId == Context.ConnectionId);
77 room.Users.Remove(user);//从房间里移除该用户
78 if (room.Users.Count <= 0)
79 {
80 DbContext.Rooms.Remove(room);//如果房间里没人了,删除该房间
81 }
82 Groups.Remove(Context.ConnectionId, room.RoomName);
83 UpdateAllRoomList();//更新房间列表
84 Clients.Client(Context.ConnectionId).removeRoom();
85 }
86 else
87 {
88 Clients.Client(Context.ConnectionId).showMessage("该房间不存在");
89 }
90 }
View Code
前端调用后台代码,使用 chat.server.方法名(参数1,参数2) 例如


1 // 开始连接服务器
2 $.connection.hub.start().done(function () {
3 $('#btnSend').click(function () {
4 var msg = $('#textMessage').val().trim();
5 if (msg == "" || msg == undefined || msg == null) {
6 alert("请输入聊天信息");
7 $('#textMessage').focus();
8 } else {
9 // 调用服务器端集线器的Send方法
10 chat.server.publicSendMsg(msg, current_userid);
11 // 清空输入框信息并获取焦点
12 $('#textMessage').val('').focus();
13 }
14 });
View Code
后台调用前端的代码。使用 chat.client.方法名。例如


1 //显示新用户加入消息
2 chat.client.showJoinMessage = function (nickName) {
3 $("#js-panel-content").append('<div class="js-time text-white text-center"><span>' + nickName + '加入了聊天</span></div>');
4 }
View Code
最后还有个保存和获取聊天记录的主要方法
1 // <summary>
2 /// 获取历史记录
3 /// </summary>
4 /// <param name="chatType">消息类型0公共聊天,1好友,2群</param>
5 /// <param name="toId">接收者id</param>
6 /// <param name="frmId">发送方id</param>
7 /// <param name="roomId">房间id</param>
8 public void GetChatHistory(int chatType =(int)ChatType.PubChat,string toId="", string frmId="",string roomId="")
9 {
10 var list = chatHistoryList;
11 var type = (ChatType)chatType;
12 switch (type)
13 {
14 case ChatType.PubChat:
15 list = chatHistoryList.Where(x => x.ChatType == type).ToList();
16 break;
17 case ChatType.PriChat:
18 //自己发送给对方的,和对方发给自己的数据集合
19 list = chatHistoryList.Where(x => x.ChatType == type && ((x.toId == toId && x.frmId == frmId) || (x.toId == frmId && x.frmId == toId))).ToList();
20 break;
21 case ChatType.GroChat:
22 list = chatHistoryList.Where(x => x.ChatType == type && x.RoomId == roomId).ToList();
23 break;
24 default:
25 list = new List<ChatHistory>();
26 break;
27 }
28 var data = JsonHelper.ToJsonString(list);
29 var user = userInfoList.FirstOrDefault(x=>x.UserID== frmId);
30 var conid = Context.ConnectionId;
31 if (user != null)
32 {
33 conid = user.ConnectionId;
34 }
35 Clients.Client(conid).initChatHistoryData(data, chatType);
36 }
37 /// <summary>
38 /// 添加历史记录数据
39 /// </summary>
40 /// <param name="name"></param>
41 /// <param name="message"></param>
42 /// <param name="chatType">0公共聊天,1私聊,2群聊</param>
43 public void AddChatHistory(ChatType chatType = 0,string userName="", string message="", string frmId="",string toId="",string roomId="")
44 {
45 ChatHistory history = new ChatHistory()
46 {
47 Hid = Guid.NewGuid().ToString().ToUpper(),
48 ChatType = chatType,
49 Message = message,
50 UserName = userName,
51 frmId = frmId,
52 toId = toId,
53 RoomId = roomId
54 };
55 chatHistoryList.Add(history);
以上就是一些主要核心代码。分享给大家共同学习,共同进步。