首先明确需求,我现在有很多个直播间,每个直播间内需要存在一个聊天室,每个聊天室内可以存在很多人聊天,当然,只有登陆系统的会员才能聊天,没有登陆的,干看着吧!

根据以上需求,可以做出三个简单的页面:登陆页面、直播列表页面、直播和聊天室页面。

一、登陆页面

登陆页面如下所示:

好简洁,有没有?

当用户成功登录之后,将用户信息保存到Session中或其他缓存中,本案例用的是Session,简单异常啊!

二、直播列表页面

直播列表页面如下所示:

本案例的侧重点在聊天室,至于直播,见他的大爷去,用图片代替!

点击任一图片,可以跳转到直播和聊天的页面!

三、直播和聊天室页面

直播和聊天室页面如下:

这个页面才是本次的重点!

接下来,主讲的就是这个页面。

我先把GroupChatHub类的代码全部贴出来,如下所示:

using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Threading.Tasks;
using MyProject.Entity;
using SignalRTest.BLL; namespace SignalRTest.Utils {
[HubName("groupChatHub")]
public class GroupChatHub:Hub {
[HubMethodName("joinRoom")]
//创建聊天的房间
public void JoinRoom(string liveId) {
try {
//查询出该房间是否开放
LiveChatRoomBLL roomBiz = new LiveChatRoomBLL();
LiveChatRoom room = roomBiz.Find(it => it.LiveID == Convert.ToInt32(liveId) && it.Status == );
//如果房间为空,则创建该聊天房间
if (room == null) {
room = new LiveChatRoom { LiveID = Convert.ToInt32(liveId), Status = };
room.ID = roomBiz.Add(room);
} if (room != null && room.ID > ) {
//将ConnectionID发送给自己
Clients.Client(Context.ConnectionId).intoRoom(Context.ConnectionId);
}
}
catch (Exception ex) {
}
} public override Task OnConnected() {
return base.OnConnected();
} public override Task OnReconnected() {
return base.OnReconnected();
} public override Task OnDisconnected(bool stopCalled) {
LiveChatRoomMemberBLL biz = new LiveChatRoomMemberBLL();
LiveChatRoomMember member = biz.Find(it => it.ConnectionID == Context.ConnectionId);
if (member != null && member.ID > ) {
//从该房间清除该人员
if (biz.Delete(member.ID)) {
//发送退出消息
Clients.Groups(new List<string> { member.RoomID.ToString() }).publishMsg(FormatMsg("系统消息", member.User.UserName + " 退出聊天", ));
//从组中移除该ConnectionID
Groups.Remove(Context.ConnectionId, member.RoomID.ToString());
}
} return base.OnDisconnected(stopCalled);
} /// <summary>
/// 发送消息,供客户端调用
/// </summary>
/// <param name="user">用户名,如果为0,则是发送给所有人</param>
/// <param name="msg">消息</param>
public void SendMsg(string user,string msg) {
LiveChatRoomMember member = new LiveChatRoomMemberBLL().Find(it => it.ConnectionID == Context.ConnectionId);
if (member != null && member.ID > ) {
Clients.Groups(new List<string> { member.RoomID.ToString() }).publishMsg(FormatMsg(member.User.UserName, msg, , member.User.HeadPic));
}
} //type 0:系统消息 1:用户消息
public static dynamic FormatMsg(string name, string msg, int type=,string pic="") {
return new {IType=type, Name=name,Msg=HttpUtility.HtmlEncode(msg),Pic= HttpUtility.HtmlEncode(pic), Time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")};
}
}
}

1、创建聊天室

当每个用户进入该页面的时候,在客户端页面中调用GroupChatHub的JoinRoom方法,JoinRoom方法的作用是创建聊天室数据并将ConnectionID发送给自己当前的页面。为何需要这样做?因为在SignalR中,每一个新连接到来,程序就会自动创建一个ConnectionID,一般的做法是将ConnectionID和UserID绑定。可是Hub不支持Session,因此在GroupChatHub类中就无法获取Session,也就无法获取当前登陆用户的信息。那怎么办呢?哼哼,简单至极!直接获取不行,我们可以进行迂回呀!反正客户端页面可以通过js调用GroupChatHub的方法,那我就将ConnectionID回传到前端页面,然后再通过ajax调用自定义的IHttpHandler接口,将ConnectionID传到接口中去和UserID进行绑定!是不是非常简单!有人会说了,IHttpHandler接口中也无法获取Session呀,你不会自己再次继承IRequiresSessionState接口哇?

上代码:

(1) 前端页面连接hub

            // 链接hub
var ticker = $.connection.groupChatHub;
$.connection.hub.start().done(function () {
//调用GroupChatHub的JoinRoom方法,创建聊天房间
ticker.server.joinRoom(QueryString("sid")).done(function () { });
});

(2) 创建房间,并将ConnectionID回传到当前页面

        [HubMethodName("joinRoom")]
//创建聊天的房间
public void JoinRoom(string liveId) {
try { //查询出该房间是否开放
LiveChatRoomBLL roomBiz = new LiveChatRoomBLL();
LiveChatRoom room = roomBiz.Find(it => it.LiveID == Convert.ToInt32(liveId) && it.Status == );
//如果房间为空,则创建该聊天房间
if (room == null) {
room = new LiveChatRoom { LiveID = Convert.ToInt32(liveId), Status = };
room.ID = roomBiz.Add(room);
} if (room != null && room.ID > ) {
//将ConnectionID发送给自己
Clients.Client(Context.ConnectionId).intoRoom(Context.ConnectionId);
}
}
catch (Exception ex) { }
}

(3) 当前页面接收回传的ConnectionID,并上送接口中

            // 接收服务端发送的消息
$.extend(ticker.client, {
intoRoom: function (data) {
//打印出当前连接的ConnectionID
//alert(data); //调用ajax接口,将当前用户的ID(Session中)与ConnectionID关联起来
var param = { action: 'joinroom', liveId: QueryString("sid"), connectionId: data };
$.ajax({
type: 'POST',
dataType: 'json',
url: 'Index.ashx',
data: JSON.stringify(param),
success: function (data) {
if (data && data.returnValue == ) {
console.log(data.returnMsg);
}
else alert(data.returnMsg);
}
});
}
});

(4) 在接口中将ConnectionID与UserID绑定

 public class JoinRoomHandler : LiveHandler<JoinRoomReq> {
public JoinRoomHandler() : base("JoinRoomHandler") { } protected override BaseResponseResult DoWork(JoinRoomReq param) {
BaseResponseResult rc = new BaseResponseResult((int)Code.OperationError, "操作失败!"); if (Index.User != null) {
if (param.liveId > ) {
//找到当前直播对应的房间号
LiveChatRoom room = new LiveChatRoomBLL().Find(it => it.LiveID == param.liveId && it.Status == );
//如果房间存在
if (room != null && room.ID > ) {
//将ConnectionID与UserID绑定到当前直播的房间中
LiveChatRoomMember member = new LiveChatRoomMember
{
ConnectionID = param.connectionId,
RoomID = room.ID,
UserID = Index.User.UserID
}; member.ID = new LiveChatRoomMemberBLL().Add(member);
//如果当前登陆的人员 成功 加入到直播聊天室
if (member.ID > ) {
//这里的代码很重要,这是在外部调用GroupChatHub
var context = GlobalHost.ConnectionManager.GetHubContext<GroupChatHub>();
//将当前的ConnectionID加入到 以房间ID为名称的组中
context.Groups.Add(param.connectionId, room.ID.ToString());
//向客户端发送新加入人员信息
context.Clients.Group(room.ID.ToString()).publishMsg(GroupChatHub.FormatMsg("系统消息", Index.User.UserName + " 加入聊天", ,Index.User.HeadPic));
rc.SetResult(,"成功加入聊天室!");
}
else
rc.SetResult(, "加入聊天房间失败!");
}
else
rc.SetResult(, "当前聊天房间不存在!");
}
else
rc.SetResult(, "当前聊天房间不存在!");
}
else
rc.SetResult(,"未登录!"); return rc;
}
}

至此,成功将当前页面的ConnectionID、登陆人员的UserID和房间号绑定了起来。

2、发送消息

发送消息就简单了,在客户端页面调用GroupChatHub类的SendMsg方法。调用如下所示:

$("#btnSend").click(function () {
//获取文本框内容
var tbxInput = $(this).parent().children(".msgs");
if (tbxInput) {
var msg = tbxInput.val() || '';
if (msg.length > ) {
// 主动发送消息,传入直播ID,和发送的内容。
ticker.server.sendMsg(QueryString("sid"), msg);
tbxInput.val('');
}
else tbxInput.focus();
}
}); $(".msgs").bind("keydown", event, function () {
if (event.keyCode == )
$("#btnSend").click();
});

SendMsg方法如下:

   public void SendMsg(string user,string msg) {
//通过ConnectionID找到当前聊天室的信息
LiveChatRoomMember member = new LiveChatRoomMemberBLL().Find(it => it.ConnectionID == Context.ConnectionId);
if (member != null && member.ID > ) {
//向当前聊天室发送消息
Clients.Groups(new List<string> { member.RoomID.ToString() }).publishMsg(FormatMsg(member.User.UserName, msg, , member.User.HeadPic));
}
}

客户端接收消息代码如下:

            // 接收服务端发送的消息
$.extend(ticker.client, {
// 接收聊天消息
publishMsg: function (data) {
if (data) {
var html = '';
//系统消息
if (data.IType == ) {
html = '<div class="im-systeminfo">'+
'<p class="im-sititle">' + data.Name + '&emsp;' + data.Time + '</p>' +
'<p class="im-sicontent">' + data.Msg + '</p>' +
'</div>';
}
//群聊消息
else if (data.IType == ) {
html = '<div class="im-contents">' +
'<img class="im-headpic" src="' + data.Pic + '"/>' +
'<div>' +
'<p class="im-nickname">' + data.Name + '&emsp;' + data.Time + '</p>' +
'<p class="im-msgs">' + data.Msg + '</p>' +
'</div>' +
'</div>';
}
} $(".im-list").append(html);
$(".im-list").scrollTop($(".im-list")[].scrollHeight);
},
intoRoom: function (data) {
//打印出当前连接的ConnectionID
//alert(data); //调用ajax接口,将当前用户的ID(Session中)与ConnectionID关联起来
var param = { action: 'joinroom', liveId: QueryString("sid"), connectionId: data };
$.ajax({
type: 'POST',
dataType: 'json',
url: 'Index.ashx',
data: JSON.stringify(param),
success: function (data) {
if (data && data.returnValue == ) {
console.log(data.returnMsg);
}
else alert(data.returnMsg);
}
});
}
});

消息收发界面如下:

3、退出聊天室

退出聊天室很简单!当用户关闭当前聊天室页面,系统就会自动调用GroupChatHub的OnDisconnected方法,我们只需在OnDisconnected方法中写入逻辑代码即可。如下所示:

 public override Task OnDisconnected(bool stopCalled) {
LiveChatRoomMemberBLL biz = new LiveChatRoomMemberBLL();
//根据ConnectionID找到当前的聊天室信息
LiveChatRoomMember member = biz.Find(it => it.ConnectionID == Context.ConnectionId);
if (member != null && member.ID > ) {
//从该房间清除该人员
if (biz.Delete(member.ID)) {
//发送退出消息
Clients.Groups(new List<string> { member.RoomID.ToString() }).publishMsg(FormatMsg("系统消息", member.User.UserName + " 退出聊天", ));
//从组中移除该ConnectionID
Groups.Remove(Context.ConnectionId, member.RoomID.ToString());
}
} return base.OnDisconnected(stopCalled);
}

界面如下所示:

至此,整个流程如上所述,一个简单的聊天室就搭建完毕啦!

源代码:https://github.com/wsjun2016/SignalRTest

演示地址:http://101.201.234.177:8090/

备注:共预配了5个账号,每个账户名都是单个数字【1,2,3,4,5】,密码都为1

SignalR 开始聊天室之旅的更多相关文章

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

    一.引言 在前一篇文章中,我向大家介绍了如何实现实现端对端聊天的功能的,在这一篇文章中将像大家如何使用SignalR实现群聊这样的功能. 二.实现思路 要想实现群聊的功能,首先我们需要创建一个房间,然 ...

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

    1.概述 通过前面几篇文章对SignalR的详细介绍.我们知道Asp.net SignalR是微软为实现实时通信的一个类库.一般情况下,SignalR会使用JavaScript的长轮询(long po ...

  3. Asp.Net SignalR - 简单聊天室实现

    简单聊天室 使用持久链接类我们就可以做一些即时通讯的应用了,我使用Group做了一个简单的聊天室,先上图技术细节下面再讲 可以加入聊天室.创建聊天室.发送消息,下面就说说我是如何通过Group做出来的 ...

  4. 使用signalR创建聊天室。

    浏览器支持Html5的情况下,SignalR使用WebSockets,当不支持时SignalR将使用其它技术来实现通讯. 界面如下:左侧包含三种聊天对象,不同的聊天对象会创建不同的对话框. 设计思路参 ...

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

    前言 交流群:195866844 上周发表了 用SignalR 2.0开发客服系统[系列1:实现群发通讯] 这篇文章,得到了很多帮助和鼓励,小弟在此真心的感谢大家的支持.. 这周继续系列2,实现聊天室 ...

  6. Asp.NET MVC 使用 SignalR 实现推送功能二(Hubs 在线聊天室 获取保存用户信息)

    简单介绍 关于SignalR的简单实用 请参考 Asp.NET MVC 使用 SignalR 实现推送功能一(Hubs 在线聊天室) 在上一篇中,我们只是介绍了简单的消息推送,今天我们来修改一下,实现 ...

  7. Asp.NET MVC 使用 SignalR 实现推送功能一(Hubs 在线聊天室)

    简介       ASP .NET SignalR 是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信.什么是实时通信的Web呢?就是让客户端(Web页面)和服务器端 ...

  8. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室 实战系列

    ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(零) 前言  http://www.cnblogs.com/panzi/p/5742089.html ASP.NET S ...

  9. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(十二) 代码重构使用反射工厂解耦(一)缓存切换

    前言 上一篇中,我们用了反射工厂来解除BLL和UI层耦合的问题.当然那是最简单的解决方法,再复杂一点的程序可能思路相同,但是在编程细节中需要考虑的就更多了,比如今天我在重构过程中遇到的问题.也是接下来 ...

随机推荐

  1. (转)winform之ListView

    一.ListView类 1.常用的基本属性: (1)FullRowSelect:设置是否行选择模式.(默认为false) 提示:只有在Details视图该属性才有意义. (2)GridLines:设置 ...

  2. C#后台Post提交XML 及接收该XML的方法

    //发送XML public void Send(object sender, System.EventArgs e)    {        string WebUrl = "http:/ ...

  3. 20170906xlVBA_RecursionGetFiles

    Dim Dic As Object Sub GetFileName() Dim FolderPath As String Set Dic = CreateObject("Scripting. ...

  4. Web版记账本开发记录(一)

    //index.js var util = require("../../utils/util.js"); //获取应用实例 var app = getApp(); Page({ ...

  5. 移动端自动化测试-Mac-IOS-Appium环境搭建

    第一步 安装JDK,本机如果带有1.7及以上版本的,则可忽略此安装步骤. 百度下载JDK,并配置环境变量 vim ~/.bash_profile 检查是否安装成功 java -version 第二步 ...

  6. php调用oracle存储

    //todo 调用oracle 存储$config = //数据库配置文件 里面包含 用户密码和host和端口以及dbname $conn = oci_connect($config['usernam ...

  7. json加密

    有的时候我们为了传参数的URL比较安全,我们一般会用json加密的方法来使自己的URL安全. $a['order_sn'] = $orderNo;$data = json_encode( $a);$d ...

  8. poj-2154-polya+euler函数

    Color Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 11758   Accepted: 3783 Descriptio ...

  9. Leetcode 980. 不同路径 III

    980. 不同路径 III  显示英文描述 我的提交返回竞赛   用户通过次数42 用户尝试次数43 通过次数46 提交次数60 题目难度Hard 在二维网格 grid 上,有 4 种类型的方格: 1 ...

  10. oracle查询视图归属于哪个用户

    select OWNER from ALL_VIEWS where VIEW_NAME='视图名';