用SignalR 2.0开发客服系统[系列2:实现聊天室]

.NetCore基于SignalR、Reids实现客服WebIM系统 WebIM客服系统,说明当前系统与自己的业务系统关联性不强。基于这个前提,最终把WebIM完善成了一个易接入、高度开放、不依赖于业务系统、支持接入多个业务系统的售后服务系统 阅读详情

前言

上周发表了

用SignalR 2.0开发客服系统[系列1:实现群发通讯]

这篇文章,得到了很多帮助和鼓励,小弟在此真心的感谢大家的支持..

这周继续系列2,实现聊天室的功能.

开发环境

开发工具:VS2013 旗舰版

数据库:未用

操作系统:WIN7旗舰版

正文开始

首先我们来看看最终效果:

正式开始:

SignalR作为一个强大的集线器,已经在hub里面集成了Gorups,也就是分组管理,使用方法如下:

//作用:将连接ID加入某个组
//Context.ConnectionId 连接ID,每个页面连接集线器即会产生唯一ID
//roomName分组的名称
Groups.Add(Context.ConnectionId, roomName);

//作用:将连接ID从某个分组移除
Groups.Remove(Context.ConnectionId, roomName);

//作用:调用分组内连接对象注册的本地JS
//XXX:本地JS名称
//Room:分组名称
// new string[0]:过滤(不发送)的连接ID数组
 Clients.Group(Room, new string[0]).XXXX

其实SignalR已经帮我们封装的很好了,关键代码其实就这三句..

废话不多说,下面开始讲我的实现.

首先实体类(参考微软Demo):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNet.SignalR;
namespace SignalRTest
{
  public class UserContext 
  {
    public UserContext()
    {
      Users = new List<User>();
      Connections = new List<Connection>();
      Rooms = new List<ConversationRoom>();
    }
    //用户集合
    public List<User> Users { get; set; }
    //连接集合
    public List<Connection> Connections { get; set; }
    //房间集合
    public List<ConversationRoom> Rooms { get; set; }
  }
  public class User
  {
    [Key]
    //用户名
    public string UserName { get; set; }
    //用户的连接
    public List<Connection> Connections { get; set; }
    //用户房间集合
    public virtual List<ConversationRoom> Rooms { get; set; }
    public User()
    {
      Connections = new List<Connection>();
      Rooms = new List<ConversationRoom>();
    }
  }
  public class Connection
  {
    //连接ID
    public string ConnectionID { get; set; }
    //用户代理
    public string UserAgent { get; set; }
    //是否连接
    public bool Connected { get; set; }
  }
  /// <summary>
  /// 房间类
  /// </summary>
  public class ConversationRoom
  {
    //房间名称
    [Key]
    public string RoomName { get; set; }
    //用户集合
    public virtual List<User> Users { get; set; }
    public ConversationRoom()
    {
      Users = new List<User>();
    }
  }
}

然后聊天室的Hub(这里我就不解释了,每句话我都加了注释,注释+代码方便大家理解..):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.Hubs;
using Newtonsoft.Json;
namespace SignalRTest
{
  [HubName("groupsHub")]
  public class GroupsHub : Hub
  {
    public static UserContext db = new UserContext();
    public void Hello()
    {
      Clients.All.hello();
    }
    /// <summary>
    /// 重写Hub连接事件
    /// </summary>
    /// <returns></returns>
    public override Task OnConnected()
    {
        // 查询用户。
        var user = db.Users.SingleOrDefault(u => u.UserName == Context.ConnectionId);
        //判断用户是否存在,否则添加
        if (user == null)
        {
          user = new User()
          {
            UserName = Context.ConnectionId
          };
          db.Users.Add(user);
        }
         //发送房间列表
        var itme = from a in db.Rooms
               select new { a.RoomName };
        Clients.Client(this.Context.ConnectionId).getRoomlist(JsonConvert.SerializeObject(itme.ToList()));
      return base.OnConnected();
    }
    /// <summary>
    /// 更新所有用户的房间列表
    /// </summary>
    private void GetRoomList()
    {
      var itme = from a in db.Rooms
             select new { a.RoomName };
      string jsondata = JsonConvert.SerializeObject(itme.ToList());
      Clients.All.getRoomlist(jsondata);
    }
    /// <summary>
    /// 重写Hub连接断开的事件
    /// </summary>
    /// <returns></returns>
    public override Task OnDisconnected()
    {
       var user = db.Users.Where(u => u.UserName == Context.ConnectionId).FirstOrDefault();
        //判断用户是否存在,存在则删除
        if (user != null)
        {
          //删除用户
          db.Users.Remove(user);
          // 循环用户的房间,删除用户
          foreach (var item in user.Rooms)
          {
            RemoveFromRoom(item.RoomName);
          }
        }
      return base.OnDisconnected();
    }
    /// <summary>
    /// 加入聊天室
    /// </summary>
    /// <param name="roomName"></param>
    public void AddToRoom(string roomName)
    {
        //查询聊天室
        var room = db.Rooms.Find(a=>a.RoomName==roomName);
         //存在则加入
        if (room != null)
        {
          //查找房间中是否存在此用户
          var isuser = room.Users.Where(a => a.UserName == Context.ConnectionId).FirstOrDefault();
          //不存在则加入
          if (isuser == null)
          {
            var user = db.Users.Find(a => a.UserName == Context.ConnectionId);
            user.Rooms.Add(room);
            room.Users.Add(user);
            Groups.Add(Context.ConnectionId, roomName);
            //调用此连接用户的本地JS(显示房间)
            Clients.Client(Context.ConnectionId).addRoom(roomName);
          }
          else
          {
            Clients.Client(Context.ConnectionId).showMessage("请勿重复加入房间!");
          }
        }
    }
    /// <summary>
    /// 创建聊天室
    /// </summary>
    /// <param name="roomName"></param>
    public void CreatRoom(string roomName)
    {
      var room = db.Rooms.Find(a => a.RoomName == roomName);
      if (room == null)
      {
        ConversationRoom cr = new ConversationRoom()
        {
          RoomName = roomName
        };
        //将房间加入列表
        db.Rooms.Add(cr);
        AddToRoom(roomName);
        Clients.Client(Context.ConnectionId).showMessage("房间创建完成!");
        GetRoomList();
      }
      else
      {
        Clients.Client(Context.ConnectionId).showMessage("房间名重复!");
      }
    }
    /// <summary>
    /// 退出聊天室
    /// </summary>
    /// <param name="roomName"></param>
    public void RemoveFromRoom(string roomName)
    {
        //查找房间是否存在
      var room = db.Rooms.Find(a => a.RoomName == roomName);
        //存在则进入删除
        if (room != null)
        {
          //查找要删除的用户
          var user = room.Users.Where(a => a.UserName == Context.ConnectionId).FirstOrDefault();
          //移除此用户
          room.Users.Remove(user);
          //如果房间人数为0,则删除房间
          if (room.Users.Count <= 0)
          {
            db.Rooms.Remove(room);
          }
          Groups.Remove(Context.ConnectionId, roomName);
          //提示客户端
          Clients.Client(Context.ConnectionId).removeRoom("退出成功!");
        }
    }
    /// <summary>
    /// 给分组内所有的用户发送消息
    /// </summary>
    /// <param name="Room">分组名</param>
    /// <param name="Message">信息</param>
    public void SendMessage(string Room, string Message)
    {
      Clients.Group(Room, new string[0]).sendMessage(Room,Message+" "+DateTime.Now.ToString());
    }
  }
}

前端HTML+JS:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <title></title>
  <script src="Scripts/jquery-1.10.2.min.js"></script>
  <script src="Scripts/jquery.signalR-2.0.0.min.js"></script>
  <!--这里要注意,这是虚拟目录,也就是你在OWIN Startup中注册的地址-->
  <script src="signalr/hubs"></script>
  <script>
    var chat
    var roomcount = 0;
    $(function () {
        chat = $.connection.groupsHub;
        chat.client.showMessage = function (Message) {
          alert(Message);
        }
        chat.client.sendMessage = function (roomname, message) {
          $("#" + roomname).find("ul").each(function () {
            $(this).append('<li>'+message+'</li>')
          })
        }
        chat.client.removeRoom = function (data) {
          alert(data);
        }
        chat.client.addRoom = function (roomname) {
          var html = '<div style="float:left; margin-left:30px; border:double" id="' + roomname + '" roomname="' + roomname + '"><button onclick="RemoveRoom(this)">退出</button>\
                  ' + roomname + '房间\
                        聊天记录如下:<ul>\
                        </ul>\
                  <input type="text" /> <button onclick="SendMessage(this)">发送</button>\
                  </div>'
          $("#RoomList").append(html);
        }
        //注册查询房间列表的方法
        chat.client.getRoomlist = function (data) {
          if (data) {
            var jsondata = $.parseJSON(data);
            $("#roomlist").html(" ");
            for (var i = 0; i < jsondata.length; i++) {
              var html = ' <li>房间名:' + jsondata[i].RoomName + '<button roomname="'+jsondata[i].RoomName+'" onclick="AddRoom(this)">加入</button></li>';
              $("#roomlist").append(html);
            }
          }
        }
        // 获取用户名称。
        $('#username').html(prompt('请输入您的名称:', ''));
        $.connection.hub.start().done(function () {
          $('#CreatRoom').click(function () {
            if (roomcount < 2) {
              chat.server.creatRoom($("#Roomname").val());
              roomcount++;
            } else {
              alert("聊天窗口只允许有2个")
            }
          })
        });
    });
    function SendMessage(btn) {
      var message = $(btn).prev().val();
      var room = $(btn).parent();
      var username = $("#username").html();
      message = username + ":" + message;
      var roomname = $(room).attr("roomname");
      chat.server.sendMessage(roomname,message);
    }
    function RemoveRoom(btn) {
      var room = $(btn).parent();
      var roomname = $(room).attr("roomname");
      chat.server.removeFromRoom(roomname);
    }
    function AddRoom(roomname) {
       var data =$(roomname).attr("roomname");
       chat.server.addToRoom(data);
    }
  </script>
</head>
<body>
  <div>
    <div>名称:<p id="username"></p></div>
    输入房间名:
    <input type="text" value="asdasd" id="Roomname" />
    <button id="CreatRoom">创建聊天室</button>
  </div>
  <div style="float:left;border:double">
    <div>房间列表</div>
    <ul id="roomlist">
    </ul>
  </div>
  <div id="RoomList">
  </div>
</body>
</html>

至此就完成了基本的聊天室功能,有许多逻辑写的不到位的情况,请大家海涵.

我会坚持写完本系列..

Asp.net MVC4 + signalR 聊天室实现 阅读详情

相关推荐

(附源码)vue3.0+.NET6实现聊天室(实时聊天SignalR)

(纯手写)基于Vue3.0+vite+.net6+SignalR等技术开发实现的网页端聊天实例项目Aerwen/Chat。实现了发送图文表情消息/gif图、emjoi表情、图片、网址查看、下拉刷新,群聊,好友发送消息...功能等功能。

weixin_60435181的博客 7027

基于ASP.NET SignalR 实现的在线通讯(客服系统)

ASP.NET SignalR 是一个面向 ASP.NET 开发人员的库,可简化将实时 web 功能添加到应用程序的过程。实时 web 功能是让服务器代码将内容推送到连接的客户端立即可用,而不是让服务器等待客户端请求新数据的能力。 SignalR 可用于将任何类型的"实时"web 功能添加到 ASP.NET 应用程序。尽管聊天通常用作示例,您可以更为很多。只要用户刷新 web 页面以查看新...

lilin的专栏 1533

Kinect V1结构光激光散斑原理及样式

   对 intel realsense F200 和 Kinect V1的coding pattern原理进行调研,知二者都使用light coding的方式,该方法与传统的coded structure light不同:传统编码结构光(空间编码,时间编码)最终使用的是三角测量的原理计算深度信息;light coding通过投射具有高度伪随机性的激光散斑,会随着不同距离变换不同

松间明月 1万+

用SignalR 2.0开发客服系统[系列4:负载均衡的情况下使用SignalR]

前言 交流群:195866844 目录: 用SignalR 2.0开发客服系统[系列1:实现群发通讯] 用SignalR 2.0开发客服系统[系列2:实现聊天室] 用SignalR 2.0开发客服系统[系列3:实现点对点通讯]    SignalR 2.0作为一个新的而且强大的通信工具,发布博客之后得到了很多人的支持,谢谢...也有人对性能和架设等问题提出了各种质疑..真的很感谢.....

weixin_34194359的博客 252

电压电流双闭环PFC单相PWM整流

电压电流双闭环PFC单相整流。仿真及代码

xht2403267701的博客 6051

Cursor Agent模式下如何优雅切换conda环境运行Python脚本?3种实用方法实测

本文针对Cursor Agent模式下运行Python脚本时环境错配的痛点,实测了三种优雅切换conda环境的实用方法。通过Shell全局配置、项目级.cursorrc文件定制以及对话中直接指令,开发者可以确保AI助手在正确的虚拟环境中执行代码,从而提升开发效率和协作流畅度。

redis7keeper的博客 597

用SignalR 2.0开发客服系统[系列1:实现群发通讯]

前言   交流群:195866844      先说一下我为什么会写这个博客吧,(首先说一下,我是一个小菜鸟,讲的不好请指导 - -,)    前段时间公司的项目涉及到在B/S上使用即时通讯,(其实就是做一个B/S的客服系统),当时公司很多大牛都说比较难搞,涉及到很多东西.   按照我的知识体系..因为之前做过C/S的即时通讯,基于Socket的..很麻烦 - -,很多坑,所以我也...

weixin_34220179的博客 169

Arduino平台软硬件原理及使用——Arduino Uno板卡的使用

Arduino Uno板卡的基本使用

洪博hopes的博客 4172

嵌入式工程闭环:从STM32到Linux的四大支柱与五步落地

嵌入式系统开发中的‘工程闭环’,是指需求、构建、部署、验证四个环节首尾咬合、可追溯、可验证的技术体系。它超越基础功能实现,聚焦工业级可靠性——如需求必须绑定ID与测试用例,构建需保证比特级确定性(如GCC版本锁定与Yocto可重现编译),部署强调零信任契约(双区OTA+ECDSA签名),验证依赖自动化栅栏(Unity/Ceedling真机测试与LAVA集群验证)。该能力直接决定项目能否通过量产考验、长期稳定运行及快速定位现场故障,是嵌入式工程师突破‘玩具级’瓶颈、迈入工业级开发的核心分水岭。

weixin_33798152的博客 296

GEE入门之路(从【初学者】角度,大白话)——附海面风速插值代码

非常初级的GEE入门教程!大白话!有手就行!附海面风速插值代码,克里金插值,时间插值。

weixin_46812066的博客 4086

IPD的分析工具与模型(十六)CBB公用基础模块管理实现资源共享,缩短开发周期降低成本

CBB流程的开发环节,基于CBB规划中所识别和设计的CBB,进行CBB的详细设计(包括参数设计和接口设计),并最终实现CBB的落地开发。作为特殊类型的技术构件,CBB的开发流程,可沿用技术开发中的构件开发流程,具体包括概念、计划、开发和迁移等步骤,具体可参见前文的相关介绍。有了蓝图与架构设计,落地实施是关键攻坚。具体工作内容包括:具体工作内容包括:a. 以相似性、聚类、相对独行性、可组合、可扩展性、可维护性等原则为指导,按照产品的功能特征和业务类型,聚焦零散的功能点,形成功能模块,实现产品功能模块的划分;

Easyways1的博客 1378

SignalR系列目录

[置顶]用SignalR 2.0开发客服系统[系列1:实现群发通讯] [置顶]用SignalR 2.0开发客服系统[系列2:实现聊天室] [置顶]用SignalR 2.0开发客服系统[系列3:实现点对点通讯] [置顶]用SignalR 2.0开发客服系统[系列4:负载均衡的情况下使用SignalR] [置顶]用SignalR 2.0开发客服系统[系列5:使用SignalR的中文简体语言包和...

weixin_34128839的博客 74

Android系统开机时间分析与优化指南

本文系统阐述了Android开机时间优化的全流程技术方案。首先详细解析了从电源键按下到桌面显示的完整启动流程及关键事件序列,然后介绍了秒表计时、日志分析和自动化脚本三种测量方法。重点从底层和上层两个维度提出了具体优化措施:底层包括编译器优化、内核驱动裁剪和日志精简;上层涵盖系统服务参数调整、应用预优化和功能组件精简。最后提供了验证工具和方法,并强调优化需要在性能、功耗和功能间取得平衡。通过这套系统化方案,可有效提升Android设备的开机速度与用户体验。

学无止境 352

史上最全面的SignalR系列教程-6、SignalR 实现聊天室

1、概述 通过前面几篇文章对SignalR的详细介绍。我们知道Asp.net SignalR是微软为实现实时通信的一个类库。一般情况下,SignalR会使用JavaScript的长轮询(long polling)的方式来实现客户端和服务器通信,随着Html5中WebSockets出现,SignalR也支持WebSockets通信。另外SignalR开发的程序不仅仅限制于宿主在IIS中,也可以宿主在...

.NET快速开发框架 1714

复旦微实现串口在线升级BOOT.BIN

将该 demo 生成的 app(升级用)和 fsbl、最简化 bit 文件(可选)打包成 BOOT.BIN,作为 golden image 烧写在 qspi flash 偏移 0 地址开始的位置,其中最简化 bit 文件为在线升级功能提供必要的物理通道(如果不需要,可以不打包该文件),golden image 一旦发布基本不需要进行升级,由该 golden image 负责和上位机进行通信交互,完成业务 app、业务 bit 文件、uboot 以及操作系统 image 等文件在线升级,在qspi flash

wangjie36的博客 3174

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

[Asp.net 开发系列之SignalR篇]专题三:使用SignalR实现聊天室的功能

[Asp.net 开发系列之SignalR篇]专题三:使用SignalR实现聊天室的功能 一、引言   在前一篇文章中,我向大家介绍了如何实现实现端对端聊天的功能的,在这一篇文章中将像大家如何使用SignalR实现群聊这样的功能。 二、实现思路   要想实现群聊的功能,首先我们需要创建一个房间,然后每个在线用户可以加入这个房间里面进行群聊,我...

fgmah2000的博客 176

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

用SignalR 2.0开发客服系统[系列5:使用SignalR的中文简体语言包和其他技术点]

前言 目录: 用SignalR 2.0开发客服系统[系列1:实现群发通讯] 用SignalR 2.0开发客服系统[系列2:实现聊天室] 用SignalR 2.0开发客服系统[系列3:实现点对点通讯] 用SignalR 2.0开发客服系统[系列4:负载均衡的情况下使用SignalR] 以上是系列目录,终于到了结束的时候了.... 为了这个系列

双鱼达摩 3020

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

上一篇: 用SignalR 2.0开发客服系统[系列1:实现群发通讯]
下一篇: 用SignalR 2.0开发客服系统[系列3:实现点对点通讯]
双鱼达摩
博客等级 码龄18年 8粉丝 4原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值