Asp.net MVC + Signalr 实现多人聊天室
Asp.net SignalR
简介:
首先简单介绍一下Signalr ,我也是刚接触,觉得挺好玩的,然后写了一个多人聊天室。
Asp.net SignalR 是为Asp.net 开发人员提供的一个库,可以简化开发人员将实时Web 功能添加到应用程序的过程。实时Web功能是指这样一种功能:当所有连接的客户端变得可用时服务器可以立即向其推送内容,而不是让服务器等待客户端请求新的数据。SignalR 提供了非常简单易用的高阶API,使用服务器端可以单个或批量调用客户端上的javaScript函数,并且非常方便地进行连接管理,例如客户端连接到服务器端,或断开连接,客户端分组,以及客户端授权,使用SignalR 都非常容易实现。
作用:
SignalR 将与客户端进行实时通信带给了ASP .NET。当然这样既好用,而且也有足够的扩展性。以前用户需要刷新页面或使用ajax轮询才能实现的实时显示数据。现在只要使用SignalR,就可以简单实现
测试结果
代码实现如下 :
首先我们创建的类需要继承 Hub 类这个类,这个类在 Microsoft.AspNet.SignalR命名空间下面。当然在使用SignalR前,需要安装SignalR相关的.dll 。右键单机项目名称 ==》 管理 NuGet 程序包 ==》 选择浏览 ==》 输入SignalR 一般就是搜索结果的第一个,选择安装就行。
安装成功之后 , 引用里面会自动引用相关的SignalR包:
安装完成之后会弹出一个页面 关于Startup.cs 的,初学者千万不要忽略,尽量去看看
之后我们要添加一个类 ==》新建项 ==》 右上角搜索start 选择OWIN Startup类 命名为Startup :此类事 .Net Web服务器和.Net Web应用之间定义的一套标准接口
Startup 类
public void Configuration(IAppBuilder app)
{
// 有关如何配置应用程序的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkID=316888
app.MapSignalR();
}
继承Hub 类 :里面有几个方法需重写:
OnConnected : 当连接连接到此集线器实例时调用。
OnDisconnected : 当连接与此集线器实例断开时调用。
OnReconnected : 当连接重新连接到此集线器实例时调用。
其他详细可参见:
https://msdn.microsoft.com/zh-cn/library/microsoft.aspnet.signalr.hub(v=vs.111).aspx
在跟目录项创建一个Hubs文件夹,然后添加 DbGroupsHub 类
HubName :指定Hub连接的名字
[HubName("dbChatRoomHub")]
public class DbGroupsHub : Microsoft.AspNet.SignalR.Hub
{
public static ContextDbData DbContext = new ContextDbData();
public string userId;
/// <summary>
/// 重写连接事件
/// </summary>
/// <returns></returns>
public override Task OnConnected()
{
// 查询用户
var user = DbContext.listChatRoom.FirstOrDefault(u => u.RoomId != null);
userId = HttpContext.Current.Request.QueryString["userid"];
var roomName = user.RoomName;
JoinRoom(roomName);
return base.OnConnected();
}
//取得在线人员列表
public void GetOnlinesUser()
{
var user = DbContext.listUsers.Where(u => u.status == 1).ToList();
List<ToolUserInfo> toolInfo = new List<ToolUserInfo>();
foreach (var item in user)
{
ToolUserInfo info = new Models.ToolUserInfo();
info.LoginId = item.LoginId.ToString();
info.roomName = item.Rooms.RoomName;
toolInfo.Add(info);
}
Clients.All.GetOnlinesUser(JsonHelper.ToJsonString(toolInfo.ToList()));
}
/// <summary>
/// 给房间内所有的用户发送消息
/// </summary>
/// <param name="room">房间名</param>
/// <param name="message">信息</param>
public void SendMessage(string room, string message)
{
// 调用房间内所有客户端的sendMessage方法
int id = Convert.ToInt32(HttpContext.Current.Request.QueryString["userid"].ToString());
var userName = DbContext.listUsers.ToList().SingleOrDefault(s => s.id == id).LoginId;
ChatRoomInfo info = new Models.ChatRoomInfo();
info.AddTime = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
info.RoomName = room;
info.Context = message;
info.LoginId = userName;
DbContext.listChatRoomInfo.Add(info);
DbContext.SaveChanges();
int thisMessageId = info.Id;
Clients.Group(room, new string[0]).sendMessage(room, message, userName, id, info.AddTime);
}
/// <summary>
/// 加入聊天室
/// </summary>
public void JoinRoom(string roomName)
{
// 查询聊天室
//var room = DbContext.Rooms.Find(p => p.RoomName == roomName);
var room = DbContext.listChatRoom.FirstOrDefault(s => s.RoomName == roomName);
// 存在则加入
if (room == null) return;
// 查找房间中是否存在此用户
var isExistUser = DbContext.listChatRoomInfo.FirstOrDefault(s => s.LoginId == userId && s.RoomName == roomName);
// 不存在则加入
if (isExistUser == null)
{
int id = Convert.ToInt32(HttpContext.Current.Request.QueryString["userid"].ToString());
var user = DbContext.listUsers.FirstOrDefault(s => s.id == id);
room.Users.Add(user);
// 将客户端的连接ID加入到组里面
Groups.Add(Context.ConnectionId, roomName);
//调用此连接用户的本地JS(显示房间)
Clients.Client(Context.ConnectionId).joinRoom(roomName);
}
}
// 重写Hub连接断开的事件
public override Task OnDisconnected(bool stopCalled)
{
// 查询用户
int id = Convert.ToInt32(HttpContext.Current.Request.QueryString["userid"].ToString());
var user = DbContext.listUsers.FirstOrDefault(u => u.id == id);
if (user != null)
{
// 删除用户
DbContext.listUsers.Remove(user);
// 从房间中移除用户
RemoveUserFromRoom(user.Rooms.RoomName);
}
return base.OnDisconnected(stopCalled);
}
/// <summary>
/// 退出
/// </summary>
/// <param name="roomName"></param>
public void RemoveUserFromRoom(string roomName)
{
//查找房间是否存在
var room = DbContext.listChatRoom.FirstOrDefault(a => a.RoomName == roomName);
// 查找要删除的用户
int id = Convert.ToInt32(HttpContext.Current.Request.QueryString["userid"].ToString());
var user = room.Users.FirstOrDefault(a => a.id == id);
user.status = 0;
DbContext.SaveChanges();
// 移除此用户
room.Users.Remove(user);
Groups.Remove(Context.ConnectionId, roomName);
//提示客户端
Clients.Client(Context.ConnectionId).removeRoom("退出成功!");
}
}
ChatRoom 类
public class ChatRoom
{
[Key]
public string RoomId { get; set; }
// 房间名称
public string RoomName { get; set; }
// 用户集合
public List<Users> Users { get; set; }
public ChatRoom()
{
Users = new List<Users>();
}
}
Users 类
public class Users
{
[Key]
public int id { get; set; }
public string LoginId { get; set; }
public string Pwd { get; set; }
public int status { get; set; } //0:未在线 1:登录在线
public SignalrStudy.Models.ChatRoom Rooms { get; set; }
}
ChatRoomInfo 类
public class ChatRoomInfo
{
[Key]
public int Id { get; set; }
public string LoginId { get; set; }
public string RoomName { get; set; }
public string Context { get; set; }
public string AddTime { get; set; }
}
MessageContext 类
public class MessageContext
{
[Key]
public int id { get; set; }
public string context { get; set; }
public string sendId { get; set; }
public string receiveId { get; set; }
}
ToolUserInfo 类
public class ToolUserInfo
{
public string LoginId { get; set; }
public string roomName { get; set; }
}
ContextDbData 类
public class ContextDbData : DbContext
{
public ContextDbData() : base("name=ChatRoomDB")
{ }
public virtual DbSet<Users> listUsers { get; set; }
public virtual DbSet<MessageContext> listMessageContext { get; set; }
public virtual DbSet<ChatRoom> listChatRoom { get; set; }
public virtual DbSet<ChatRoomInfo> listChatRoomInfo { get; set; }
}
走到现在服务器代码基本写好了,现在我们开始前端建立连接。
首先引入我们需要的js文件
<script src="~/Scripts/jquery-2.2.2.min.js"></script>
<script src="~/Scripts/jquery.signalR-2.2.2.min.js"></script>
<!--这里要注意,这是虚拟目录,也就是你在OWIN Startup中注册的地址-->
<script src="/signalr/hubs"></script>
<script type="text/javascript">
var chat;
var userId;
$(function () {
userId = GetRequest();
$.connection.hub.qs = { 'userid': userId.Id }
//此处为建立连接 dbChatRoomHub 为DbGroupsHub 类的 HubName标识属性
chat = $.connection.dbChatRoomHub;
//After Service connection
$.connection.hub.start().done(function () {
chat.server.getOnlinesUser();
});
//Get Current online users
chat.client.GetOnlinesUser = function (data) {
if (data)
{
var jsondata = $.parseJSON(data);
$(".Name").text(jsondata[0].roomName);
$("#OnLineUser").html(" ");
for (var i = 0; i < jsondata.length; i++) {
var html = '<li>' + jsondata[i].LoginId + '</li>';
$("#OnLineUser").append(html);
}
}
}
//Receive Message
chat.client.sendMessage = function (room, message, userName, id, time) {
if (userId.Id == id) {
var html = '<li style="list-style:none;float:right;margin-top:15px;"><lable style="margin-right:40px;">' + time + '</lable><lable style="margin-right:20px;">' + userName + '</lable></br><lable style="margin-right:30px;">' + message + '</lable></li></br>';
$("#messageContext").append(html);
}
else {
var html = '<li style="list-style:none;float:left; margin-left:20px;margin-top:15px;"><lable>' + userName + '</lable><lable style="margin-left:40px;">' + time + '</lable></br> <lable>' + message + '</lable></li></br>';
$("#messageContext").append(html);
}
};
//Post exit operation
chat.client.removeRoom = function (data) {
alert(data);
};
//Send Message
$("#btnSend").click(function () {
var roomname = $(".Name").text();
var message = $("#message").val();
chat.server.sendMessage(roomname, message);
$("#message").val('');
$("#message").focus();
})
//Sign Out ChatRoom
$("#signout").click(function () {
var roomname = $(".Name").text();
chat.server.removeUserFromRoom(roomname);
})
//获取url中的参数
function GetRequest() {
var url = location.search; //获取url中"?"符后的字串
var theRequest = new Object();
if (url.indexOf("?") != -1) {
var str = url.substr(1);
strs = str.split("&");
for (var i = 0; i < strs.length; i++) {
theRequest[strs[i].split("=")[0]] = unescape(strs[i].split("=")[1]);
}
}
return theRequest;
}
});
</script>
<body style="margin-left:300px;">
<input type="hidden" id="hiddenVal" value="" />
<div>欢迎来到<label class="Name"></label></div>
<div style="margin-top:40px;">
<div style="float:left">
<div id="messageContext" style="width:450px;height:400px;border:1px solid #808080">
<ul id="messageContext" style="list-style:none">
</ul>
</div>
</div>
<div style="width:190px;height:400px;border:1px solid #808080;float:right;margin-right:800px;">
在线的用户:
<ul id="OnLineUser">
</ul>
</div>
<div><input type="button" value="退 出" id="signout"/></div>
</div>
<div style="margin-top:15px;">
<input type="text" id="message" style="width:300px;height:30px;border:1px solid #808080" />
<input type="button" value="发 送" id="btnSend" />
</div>
</body>
提示:别忘了web.Config中的连接字符串
写的不好欢迎提意见,我也是初学者,谢谢......
Asp.net MVC + Signalr 实现多人聊天室的更多相关文章
- AngularJS+ASP.NET MVC+SignalR实现消息推送
原文:AngularJS+ASP.NET MVC+SignalR实现消息推送 背景 OA管理系统中,员工提交申请单,消息实时通知到相关人员及时进行审批,审批之后将结果推送给用户. 技术选择 最开始发现 ...
- ASP.Net MVC SignalR的应用
ASP.Net MVC SignalR的应用 最近做的一个MVC项目有个模块是要使用即时通信实现弹幕效果.既要考虑通信的实时性也要考虑服务器性能和资源消耗,所幸项目对浏览器的版本没有要求.所以我最先想 ...
- asp.net MVC SignalR 与数据库 实时同步显示
asp.net MVC SignalR 与数据库 实时同步显示 错误:未启用当前数据库的 SQL Server Service Broker,因此查询通知不受支持.如果希望使用通知,请为此数据库启用 ...
- ASP.NET MVC SignalR(1):背景
系列目录:ASP.NET MVC SignalR 关键词:HTTP.轮询.WebSocket.Server-Sent Events.长轮询.forever frame. 1. HTTP HTTP(Hy ...
- [SignalR]一个简单的聊天室
原文:[SignalR]一个简单的聊天室 1.说明 开发环境:Microsoft Visual Studio 2010 以及需要安装NuGet. 2.添加SignalR所需要的类库以及脚本文件: 3. ...
- SignalR 入门 .netCore实现聊天室
SignalR 入门 .netCore实现聊天室 本文根据微软SignalR 简介 | Microsoft Docs 和 ASP.NET Core SignalR 简介 | Microsoft Doc ...
- Apache MiNa 实现多人聊天室
Apache MiNa 实现多人聊天室 开发环境: System:Windows JavaSDK:1.6 IDE:eclipse.MyEclipse 6.6 开发依赖库: Jdk1.4+.mina-c ...
- 与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室
原文:与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...
- 与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室
原文:与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...
随机推荐
- 纯C++安卓开发 (ndk)系列之 ---- 常见问题
常见问题1:run as Android Application运行时提示无法识别到模拟器 解决步骤如下: (1)首先查看安卓模拟器是否已经打开 (2)如果安卓模拟器已经打开,则操作步骤为:点击Ecl ...
- Chapter 3 Phenomenon——12
Naturally, the ambulance got a police escort to the county hospital. 自然而然的,救护车让一个警察陪护到县医院去. 自然,救护车一路 ...
- 10-hdfs-hdfs搭建
hdfs的优缺点比较: 架构图解分析: nameNode的主要任务: SNameNode的功能: (不是NN的备份, 主要用来合并fsimage) 合并流程: dataNode的主要功能: HDFS上 ...
- 什么是Java序列化?为什么序列化?序列化有哪些方式?
先普及一下,计算机中无法识别一个基本单元[字节]来表示,必须经过“翻译”才能让计算机理解人类的语言,这个翻译过程就是[编码],通常所说的字符转换为字节. 有I/O的地方机就会涉及编码,现在几乎所有的 ...
- Mongodb添加副本及修改优先级
Mongodb添加副本及修改优先级 1.添加副本集 #在primary节点上执行 >rs.add( { host: "192.168.1.11:27017", priorit ...
- Linux内核编程规范与代码风格
source: https://www.kernel.org/doc/html/latest/process/coding-style.html translated by trav, travmym ...
- css3的overflow-anchor
overflow-anchor属性使我们能够选择退出滚动锚定,这是一个浏览器特性,旨在允许内容在用户当前的DOM位置上加载,而不需要在内容完全加载后更改用户的位置. 为何要有这个属性? 滚动锚定是一种 ...
- Node.js链式回调
由于异步的关系,代码的书写顺序可能和执行顺序并不一样,可能想先执行A再执行B,但由于异步可能B要先于A执行.例如在OC中使用AFnetworking请求数据然后刷新页面,由于网络请求是用block实现 ...
- 关于Sqlite的一个demo
直接上代码: class DBHelperSqlite { ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetC ...
- JavaScript 正则表达式RegExp 和字符串本身的正则表达式
JavaScript 正则表达式 正则表达式(英语:Regular Expression,在代码中常简写为regex.regexp或RE)使用单个字符串来描述.匹配一系列符合某个句法规则的字符串搜索模 ...