ASP.NET SignalR实现一个简单的聊天室

来源:-小确幸

cnblogs.com/wwym/p/8780798.html

什么是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 userInfoList = new List();

protected static SignalRContext DbContext = new SignalRContext();

protected static List chatHistoryList = new List();

#endregion

#region 连接

///

/// 客户端重连接时

///

///

public override Task OnConnected()

{

AddUserGroup();//添加用户组

UpdateAllRoomList();//更新房间列表

return base.OnConnected();

}

///

/// 断线

///

///

///

public override Task OnDisconnected(bool stopCalled)

{

return base.OnDisconnected(stopCalled);

}

#endregion

}

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

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

2)、开始连接服务器

公共聊天方法

#region 公共聊天

///

/// 公共聊天

///

///

///

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

一对一聊天方法

///

/// 发送私聊消息

///

///

发送名称

///

用户id

///

消息

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, "");

}

}

多对多聊天,群聊方法

///

/// 创建聊天室

///

///

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");

}

}

///

///加入聊天室

///

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[0]).showSysGroupMsg(u.UserName);

}

}

else

{

Clients.Client(Context.ConnectionId).showMessage("该群组不存在");

}

}

///

/// 给指定房间内的所有用户发消息

///

///

房间名

///

消息

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[0]).showGroupByRoomMsg(user.UserName,room.RoomId, message);

AddChatHistory(ChatType.GroChat, user.UserName, message, user.UserID, "", room.RoomId);

}

}

///

/// 退出房间

///

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) 例如

// 开始连接服务器

$('#btnSend').click(function () {

var msg = $('#textMessage').val().trim();

if (msg == "" || msg == undefined || msg == null) {

alert("请输入聊天信息");

$('#textMessage').focus();

} else {

// 调用服务器端集线器的Send方法

// 清空输入框信息并获取焦点

$('#textMessage').val('').focus();

}

});

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

//显示新用户加入消息

$("#js-panel-content").append('

' + nickName + '加入了聊天

');

}

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

//

/// 获取历史记录

///

///

消息类型0公共聊天,1好友,2群

///

接收者id

///

发送方id

///

房间id

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();

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);

}

///

/// 添加历史记录数据

///

///

///

///

0公共聊天,1私聊,2群聊

public void AddChatHistory(ChatType chatType = 0,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

看完本文有收获?请转发分享给更多人

关注「DotNet」,提升.Net技能

淘口令:复制以下红色内容,再打开手淘即可购买

范品社,使用¥极客T恤¥抢先预览(长按复制整段文案,打开手机淘宝即可进入活动内容)

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180526B0LFBB00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券