热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用ASP.NETSignalR实现一个简单的聊天室

前言距离我写上一篇博客已经又过了一年半载了,时间过得很快,一眨眼,就把人变得沧桑了许多。青春是短暂的,知识是无限的。要用短暂的青春,去学无穷无尽的知识,及时当勉励,岁月不待人。今天

 前言

  距离我写上一篇博客已经又过了一年半载了,时间过得很快,一眨眼,就把人变得沧桑了许多。青春是短暂的,知识是无限的。要用短暂的青春,去学无穷无尽的知识,及时当勉励,岁月不待人。今天写个随笔小结记录一下。

 什么是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 userInfoList = new List();
 6         protected static SignalRContext DbCOntext= new SignalRContext();
 7         protected static List chatHistoryList = new List();
 8         #endregion
 9 
10         #region 连接
11       
12         /// 
13         /// 客户端重连接时
14         /// 
15         /// 
16         public override Task OnConnected()
17         {
18             AddUserGroup();//添加用户组
19             UpdateAllRoomList();//更新房间列表
20 
21             return base.OnConnected();
22         }
23         /// 
24         /// 断线
25         /// 
26         /// 
27         /// 
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         /// 
 4         /// 公共聊天
 5         /// 
 6         /// 
 7         /// 
 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  /// 
 2         /// 发送私聊消息
 3         /// 
 4         /// 发送名称
 5         /// 用户id
 6         /// 消息
 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  /// 
 2         /// 创建聊天室
 3         /// 
 4         /// 
 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         /// 
26         ///加入聊天室
27         /// 
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         /// 
53         /// 给指定房间内的所有用户发消息
54         /// 
55         /// 房间名
56         /// 消息
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         /// 
69         /// 退出房间
70         /// 
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(
+ nickName + 加入了聊天
); 4 }
View Code

 最后还有个保存和获取聊天记录的主要方法

 1        // 
 2         /// 获取历史记录
 3         /// 
 4         /// 消息类型0公共聊天,1好友,2群
 5         /// 接收者id
 6         /// 发送方id
 7         /// 房间id
 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();
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         /// 
38         /// 添加历史记录数据
39         /// 
40         /// 
41         /// 
42         /// 0公共聊天,1私聊,2群聊
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); 

以上就是一些主要核心代码。分享给大家共同学习,共同进步。

使用ASP.NET SignalR实现一个简单的聊天室


推荐阅读
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 本文介绍了使用AJAX的POST请求实现数据修改功能的方法。通过ajax-post技术,可以实现在输入某个id后,通过ajax技术调用post.jsp修改具有该id记录的姓名的值。文章还提到了AJAX的概念和作用,以及使用async参数和open()方法的注意事项。同时强调了不推荐使用async=false的情况,并解释了JavaScript等待服务器响应的机制。 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • 本文讲述了作者通过点火测试男友的性格和承受能力,以考验婚姻问题。作者故意不安慰男友并再次点火,观察他的反应。这个行为是善意的玩人,旨在了解男友的性格和避免婚姻问题。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 后台获取视图对应的字符串
    1.帮助类后台获取视图对应的字符串publicclassViewHelper{将View输出为字符串(注:不会执行对应的ac ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 在project.properties添加#Projecttarget.targetandroid-19android.library.reference.1..Sliding ... [详细]
author-avatar
kevin_xi
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有