• 使用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); 

    以上就是一些主要核心代码。分享给大家共同学习,共同进步,代码方面欢迎各位大佬指点。
    后期补充:github地址

    ASP.NET SignalR+MVC+BootStrap:https://github.com/wyanmei/SignalRChat

    前后端分离的部分,我做成了两个项目,ASP.NET SignalR+WepApi+BootStrap+Vue.js
    WebApi后端项目地址:https://github.com/wyanmei/SignalRChatForWebApi
    Vue.js前端项目地址:https://github.com/wyanmei/SignalRChatForVue




  • 相关阅读:
    Processing编程【2】
    哈工大锐捷网络处理问题
    processing编程【1】
    verilog入门知识【2】
    数字电路与逻辑设计知识清单【一】
    四位密码锁*电子密码锁的设计
    verilog入门知识【1】
    【Android】入门的一些知识。
    Andriod 入门
    关于Hibernate和Strtus2的xml提示问题
  • 原文地址:https://www.cnblogs.com/wwym/p/8780798.html
Copyright © 2020-2023  润新知