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>&nbsp;&nbsp;&nbsp;&nbsp;<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 实现多人聊天室的更多相关文章

  1. AngularJS+ASP.NET MVC+SignalR实现消息推送

    原文:AngularJS+ASP.NET MVC+SignalR实现消息推送 背景 OA管理系统中,员工提交申请单,消息实时通知到相关人员及时进行审批,审批之后将结果推送给用户. 技术选择 最开始发现 ...

  2. ASP.Net MVC SignalR的应用

    ASP.Net MVC SignalR的应用 最近做的一个MVC项目有个模块是要使用即时通信实现弹幕效果.既要考虑通信的实时性也要考虑服务器性能和资源消耗,所幸项目对浏览器的版本没有要求.所以我最先想 ...

  3. asp.net MVC SignalR 与数据库 实时同步显示

    asp.net MVC SignalR 与数据库 实时同步显示 错误:未启用当前数据库的 SQL Server Service Broker,因此查询通知不受支持.如果希望使用通知,请为此数据库启用 ...

  4. ASP.NET MVC SignalR(1):背景

    系列目录:ASP.NET MVC SignalR 关键词:HTTP.轮询.WebSocket.Server-Sent Events.长轮询.forever frame. 1. HTTP HTTP(Hy ...

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

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

  6. SignalR 入门 .netCore实现聊天室

    SignalR 入门 .netCore实现聊天室 本文根据微软SignalR 简介 | Microsoft Docs 和 ASP.NET Core SignalR 简介 | Microsoft Doc ...

  7. Apache MiNa 实现多人聊天室

    Apache MiNa 实现多人聊天室 开发环境: System:Windows JavaSDK:1.6 IDE:eclipse.MyEclipse 6.6 开发依赖库: Jdk1.4+.mina-c ...

  8. 与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室

    原文:与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...

  9. 与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室

    原文:与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...

随机推荐

  1. Ruby on Rails Mountable vs. Full Engine

    原文 :https://www.travisluong.com/ruby-on-rails-mountable-vs-full-engine/一个Rails Engine 本质是一个 Rails ap ...

  2. nginx 超时问题: upstream timed out (110: Connection timed out) while reading response header from upstream

    目录 错误内容 错误原因 错误解决办法 错误内容 我们可以在error.log 里面可以看到 错误内容:upstream timed out (110: Connection timed out) w ...

  3. C#的TextBox获取行高

    当TextBox使用多行之后,如果想获取每行的高度,似乎有点问题, TextBox.Height获取的是控件的高度, 而我们常做的是根据行的数量来决定是否要显示滚动条 如下: //不能直接获取每行的高 ...

  4. redis实战笔记(5)-第5章 使用 Redis构建支持程序

    本章主要内容 1.使用Redis记录日 志 2.使用Redis实现计数器并进行数据统计 3.查询IP地址所属的城市与国家 4.服务的发现与配置   这一章将介绍如何使用Redis来帮助和支持系统的其他 ...

  5. C# 在同一个项目里启动不同的类文件

    比如有两个类文件分别为 Person.cs 和 Enum.cs : using System; using person; namespace HelloWorld { class HelloWorl ...

  6. MySQL常用命令操作

    1. 命令行登录使用默认3306端口的MySQL: mysql -u root -p 2. 通过TCP连接管理不同端口的多个MySQL(注意:MySQL4.1以上版本才有此项功能): mysql -u ...

  7. 网页3D效果库Three.js学习[二]-了解照相机

    camera 上篇大致了解了three.js ,并可以创建一个简单的可动的立方体.下来我们着重了解下camera (照相机),照相机其实就是视角,就像你的眼睛.Three.js有两种不同的相机模式:直 ...

  8. 微信 weui 初体验

    最近微信推出他们自己的H5组件(weui)组件的优点有两个: 做为开发者的我们可以不用写太多css,直接拿过来就可以用. 组件都有点击态,大大增加了用户的体验好感 高清屏幕下 border : 0.5 ...

  9. Mapped Statements collection does not contain value for 问题的解决

    在做SSM项目的时候,遇到MyBatis抛出的一个异常: Mapped Statements collection does not contain value for org.lyk.vo.mapp ...

  10. WireShark 过滤 SSDP

    在局域网中使用wireshark抓包过滤http的时候经常会出现一些干扰协议,例如SSDP,使用过滤条件"http"有可能出现N多ssdp包,如下图所示: SSDP:Simple ...