前言

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

 什么是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 类来配置应用.

 [assembly: OwinStartup(typeof(SignalRChat.Startup))]
namespace SignalRChat
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
}

 我的项目结构

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

重点在创建的ChatHub集线器中

  [HubName("chatHub")]
public class ChatHub : Hub
{
#region 全局对象
protected static List<UserInfo> userInfoList = new List<UserInfo>();
protected static SignalRContext DbContext = new SignalRContext();
protected static List<ChatHistory> chatHistoryList = new List<ChatHistory>();
#endregion #region 连接 /// <summary>
/// 客户端重连接时
/// </summary>
/// <returns></returns>
public override Task OnConnected()
{
AddUserGroup();//添加用户组
UpdateAllRoomList();//更新房间列表 return base.OnConnected();
}
/// <summary>
/// 断线
/// </summary>
/// <param name="stopCalled"></param>
/// <returns></returns>
public override Task OnDisconnected(bool stopCalled)
{
return base.OnDisconnected(stopCalled);
}
#endregion

1)前端引用自动生成得集线器代理对象

var chat = $.connection.chatHub;注意红色标明得注意取 HubName中得名称,如果hubname没注释,就取集线器类中得类名首字母小写。

2) 开始连接服务器
   $.connection.hub.start().done(function () {  });

公共聊天方法

  #region 公共聊天

         /// <summary>
/// 公共聊天
/// </summary>
/// <param name="message"></param>
/// <param name="name"></param>
public void PublicSendMsg(string message, string userId)
{
var user = userInfoList.FirstOrDefault(x => x.UserID == userId);
Clients.All.sendPublicMessage(user.UserID, user.UserName, message);
AddChatHistory(ChatType.PubChat,user.UserName, message, user.UserID,"");//添加历史记录
}
#endregion

一对一聊天方法

  /// <summary>
/// 发送私聊消息
/// </summary>
/// <param name="sendName">发送名称</param>
/// <param name="userId">用户id</param>
/// <param name="message">消息</param>
public void SendPrivateMsg(string sendName, string userId, string message)
{
var toUser = userInfoList.FirstOrDefault(x => x.UserID == userId);//接收用户信息
var fromUser = userInfoList.FirstOrDefault(x => x.ConnectionId == Context.ConnectionId);//发送用户信息
if (toUser != null && fromUser != null)
{
Clients.Caller.showMsgToPages(fromUser.UserID, sendName, message);
if (fromUser.UserID != userId)//判断是否是自己给自己发消息
{
Clients.Client(toUser.ConnectionId).remindMsg(fromUser.UserID, fromUser.UserName,message);
}
AddChatHistory(ChatType.PriChat, sendName, message, fromUser.UserID, userId, "");
}
}

多对多聊天,群聊方法

  /// <summary>
/// 创建聊天室
/// </summary>
/// <param name="roomName"></param>
public void CreateRoom(string roomName)
{
var room = DbContext.Rooms.Find(x => x.RoomName == roomName);
if (room == null)
{
var rom = new ChatRoom
{
RoomName = roomName,
RoomId = Guid.NewGuid().ToString().ToUpper()
};
DbContext.Rooms.Add(rom);//加入房间列表
UpdateAllRoomList();//更新房间列表
Clients.Client(Context.ConnectionId).showGroupMsg("success");
}
else
{
Clients.Client(Context.ConnectionId).showGroupMsg("error");
}
} /// <summary>
///加入聊天室
/// </summary>
public void JoinRoom(string roomId,string current_Id)
{
// 查询聊天室,
var room = DbContext.Rooms.Find(x => x.RoomId == roomId.Trim());
var u = userInfoList.Find(x => x.UserID == current_Id);
if (room != null)
{
//检测该用户是否存在在该房间
var isExistUser = room.Users.Find(x => x.UserConnectionId == Context.ConnectionId);
if (isExistUser == null)
{
var user = DbContext.Users.Find(x => x.UserConnectionId == Context.ConnectionId);
user.Rooms.Add(room);//用户信息中加入房间信息
room.Users.Add(user);//房间信息中加入用户信息
Groups.Add(Context.ConnectionId, room.RoomName);//添加到组中
Clients.Group(room.RoomName, new string[]).showSysGroupMsg(u.UserName);
}
}
else
{
Clients.Client(Context.ConnectionId).showMessage("该群组不存在");
}
} /// <summary>
/// 给指定房间内的所有用户发消息
/// </summary>
/// <param name="room">房间名</param>
/// <param name="message">消息</param>
public void SendMessageByRoom(string roomId, string current_Id, string message)
{
var room = DbContext.Rooms.FirstOrDefault(x=>x.RoomId==roomId);
var user = userInfoList.Find(x => x.UserID == current_Id);
if (room != null && user != null)
{
Clients.Group(room.RoomName, new string[]).showGroupByRoomMsg(user.UserName,room.RoomId, message);
AddChatHistory(ChatType.GroChat, user.UserName, message, user.UserID, "", room.RoomId);
}
} /// <summary>
/// 退出房间
/// </summary>
public void RemoveRoom(string roomId)
{
var room = DbContext.Rooms.Find(x => x.RoomId == roomId);
if (room != null)
{
var user = DbContext.Users.Find(x => x.UserConnectionId == Context.ConnectionId);
room.Users.Remove(user);//从房间里移除该用户
if (room.Users.Count <= )
{
DbContext.Rooms.Remove(room);//如果房间里没人了,删除该房间
}
Groups.Remove(Context.ConnectionId, room.RoomName);
UpdateAllRoomList();//更新房间列表
Clients.Client(Context.ConnectionId).removeRoom();
}
else
{
Clients.Client(Context.ConnectionId).showMessage("该房间不存在");
}
}

前端调用后台代码,使用  chat.server.方法名(参数1,参数2) 例如

   // 开始连接服务器
$.connection.hub.start().done(function () {
$('#btnSend').click(function () {
var msg = $('#textMessage').val().trim();
if (msg == "" || msg == undefined || msg == null) {
alert("请输入聊天信息");
$('#textMessage').focus();
} else {
// 调用服务器端集线器的Send方法
chat.server.publicSendMsg(msg, current_userid);
// 清空输入框信息并获取焦点
$('#textMessage').val('').focus();
}
});

后台调用前端的代码。使用 chat.client.方法名。例如

  //显示新用户加入消息
chat.client.showJoinMessage = function (nickName) {
$("#js-panel-content").append('<div class="js-time text-white text-center"><span>' + nickName + '加入了聊天</span></div>');
}

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

 1        // <summary>
/// 获取历史记录
/// </summary>
/// <param name="chatType">消息类型0公共聊天,1好友,2群</param>
/// <param name="toId">接收者id</param>
/// <param name="frmId">发送方id</param>
/// <param name="roomId">房间id</param>
public void GetChatHistory(int chatType =(int)ChatType.PubChat,string toId="", string frmId="",string roomId="")
{
var list = chatHistoryList;
var type = (ChatType)chatType;
switch (type)
{
case ChatType.PubChat:
list = chatHistoryList.Where(x => x.ChatType == type).ToList();
break;
case ChatType.PriChat:
//自己发送给对方的,和对方发给自己的数据集合
list = chatHistoryList.Where(x => x.ChatType == type && ((x.toId == toId && x.frmId == frmId) || (x.toId == frmId && x.frmId == toId))).ToList();
break;
case ChatType.GroChat:
list = chatHistoryList.Where(x => x.ChatType == type && x.RoomId == roomId).ToList();
break;
default:
list = new List<ChatHistory>();
break;
}
var data = JsonHelper.ToJsonString(list);
var user = userInfoList.FirstOrDefault(x=>x.UserID== frmId);
var conid = Context.ConnectionId;
if (user != null)
{
conid = user.ConnectionId;
}
Clients.Client(conid).initChatHistoryData(data, chatType);
}
/// <summary>
/// 添加历史记录数据
/// </summary>
/// <param name="name"></param>
/// <param name="message"></param>
/// <param name="chatType">0公共聊天,1私聊,2群聊</param>
public void AddChatHistory(ChatType chatType = ,string userName="", string message="", string frmId="",string toId="",string roomId="")
{
ChatHistory history = new ChatHistory()
{
Hid = Guid.NewGuid().ToString().ToUpper(),
ChatType = chatType,
Message = message,
UserName = userName,
frmId = frmId,
toId = toId,
RoomId = roomId
};
 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

使用ASP.NET SignalR实现一个简单的聊天室的更多相关文章

  1. [SignalR]一个简单的聊天室

    原文:[SignalR]一个简单的聊天室 1.说明 开发环境:Microsoft Visual Studio 2010 以及需要安装NuGet. 2.添加SignalR所需要的类库以及脚本文件: 3. ...

  2. 用ServletContext做一个简单的聊天室

    这里主要是ServletContext的一个特性:ServletContext是一个公共的空间,可以被所有的客户访问.由此可见ServletContext比cookie和session的作用范围要大[ ...

  3. 基于websocket实现的一个简单的聊天室

    本文是基于websocket写的一个简单的聊天室的例子,可以实现简单的群聊和私聊.是基于websocket的注解方式编写的.(有一个小的缺陷,如果用户名是中文,会乱码,不知如何处理,如有人知道,请告知 ...

  4. ASP.NET Signalr 2.0 实现一个简单的聊天室

    学习了一下SignalR 2.0,http://www.asp.net/signalr 文章写的很详细,如果头疼英文,还可以机翻成中文,虽然不是很准确,大概还是容易看明白. 理论要结合实践,自己动手做 ...

  5. WebSocket介绍和一个简单的聊天室

    WebSocket是什么呢? WebSocket一种在单个 TCP 连接上进行全双工通讯的协议.WebSocket通信协议于2011年被IETF定为标准RFC 6455,并被RFC7936所补充规范, ...

  6. 如何用WebSocket实现一个简单的聊天室以及单聊功能

    百度百科中这样定义WebSocket:WebSocket协议是基于TCP的一种新的网络协议.它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端.简单的说,We ...

  7. node实现一个简单的聊天室(认识一下socket)

    边学边理解node的高深,今天写了一个聊天室的demo,很简单,认识一下socket node服务端代码 var express = require('express'); var app = exp ...

  8. 利用JavaUDPSocket+多线程模拟实现一个简单的聊天室程序

    对Socket的一点个人理解:Socket原意是指插座.家家户户都有五花八门的家用电器,但它们共用统一制式的插座.这样做的好处就是将所有家用电器的通电方式统一化,不需要大费周章地在墙壁上凿洞并专门接电 ...

  9. 通过WebSocket实现一个简单的聊天室功能

    WebSocket WebSocket是一个协议,它是是基于TCP的一种新的网络协议,TCP协议是一种持续性的协议,和HTTP不同的是,它可以在服务器端主动向客户端推送消息.通过这个协议,可以在建立一 ...

随机推荐

  1. 如何启用Oracle EBS Form监控

    前言: 有时候,因某些需要,必须知道Oracle的Form被使用的情况,以方面我们做出决策: 例如,如果某个Form被使用的次数非常多,那么,这个Form的相关SQL代码就应该优先处理,以减少服务器负 ...

  2. 【一天一道LeetCode】#86. Partition List

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given a ...

  3. Leetcode_58_Length of Last Word

    Given a string s consists of upper/lower-case alphabets and empty space characters ' ', return the l ...

  4. FilterDispatcher is depredated!plesae use the new filters

    一些struts2的教程都是比较早的,当我们基于较新版本的struts2来实现代码的时候,往往会出现一些问题.比如这个警告:FilterDispatcher isdeprecated! 在web.xm ...

  5. 【一天一道LeetCode】#68. Text Justification

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given a ...

  6. HTML DOCTYPE 的重要性

    定义和用法 <!DOCTYPE> 声明必须是 HTML 文档的第一行,位于 <html> 标签之前. <!DOCTYPE> 声明不是 HTML 标签:它是指示 we ...

  7. mysql进阶(十)不靠谱的FLOAT数据类型

    今天在设计数据表时,突然发现原来FLOAT原来是很不靠谱的,所以在这里建议大家换成DOUBLE类型, 原因是: 在mysql手册中讲到,在MySQL中的所有计算都是使用双精度完成的,使用float(单 ...

  8. AngularJS进阶(十)AngularJS改变元素显示状态

    AngularJS改变元素显示状态 前言 本文描述使用AngularJS提供的ng-show和ng-hide指令实现自动监听某布尔型变量来改变元素显示状态. 控制html元素显示和隐藏有n种方法:ht ...

  9. MySQL内存调优

    原文链接: MySQL Memory Allocation -- by Rick James原文日期: Created 2010; Refreshed Oct, 2012, Jan, 2014 翻译人 ...

  10. Linux常用命令(第二版) --网络通信命令

    网络通信命令 1.write /usr/bin/write 格式: write [用户名] #用于向用户发送信息,前提是这个用户已经登录到了这台服务器主机,不然的话,也没有办法给他留言,所以,writ ...