>  기사  >  백엔드 개발  >  Asp.net은 SignalR을 사용하여 채팅방 기능을 구현합니다.

Asp.net은 SignalR을 사용하여 채팅방 기능을 구현합니다.

高洛峰
高洛峰원래의
2016-12-24 14:20:381872검색

1. 소개
이전 기사 "Asp.net은 SignalR을 사용하여 멋진 엔드투엔드 채팅 기능을 구현합니다"에서 엔드투엔드 채팅 기능을 구현하는 방법을 소개했습니다. 이번 글에서는 SignalR을 사용하여 그룹 채팅과 같은 기능을 구현하는 방법을 알아봅니다.

2. 구현 아이디어
그룹 채팅 기능을 구현하려면 먼저 방을 만들어야 하며, 각 온라인 사용자가 이 방에 그룹 채팅에 참여할 수 있습니다. 방에 고유한 사용자 이름을 설정할 수 있습니다. 이름은 식별자 역할을 합니다. SignalR 클래스 라이브러리에 이러한 기존 메서드가 있습니까? 대답은 '예'입니다.

// IGroupManager接口提供如下方法
// 作用:将连接ID加入某个组
// Context.ConnectionId 连接ID,每个页面连接集线器即会产生唯一ID
// roomName分组的名称
Groups.Add(Context.ConnectionId, roomName);
 
// 作用:将连接ID从某个分组移除
Groups.Remove(Context.ConnectionId, roomName);
 
// IHubConnectionContext接口提供了如下方法
// 调用客户端方法向房间内所有用户群发消息
// Room:分组名称
// new string[0]:过滤(不发送)的连接ID数组
 Clients.Group(Room, new string[0]).clientMethod


위 코드는 그룹 채팅 구현의 핵심 메소드입니다. 직설적으로 말하면 Groups 개체는 SignalR 클래스 라이브러리에 의해 유지되는 목록 개체일 뿐입니다. 실제로 우리는 방을 만들 때 방을 추가하여 Dictionary> 개체를 유지할 수 있습니다. 이 사전에 클라이언트의 ConnectionId가 추가되고, 채팅방에서 메시지 보내기를 클릭하면 방 이름을 기준으로 그룹 채팅에 참여하는 모든 ConnectionId를 찾아 호출합니다. Clients.Clients(IListconnectionIds) 메서드를 사용하여 모든 클라이언트에 브로드캐스트 메시지를 보냅니다. 이상이 채팅방 구현의 원리이다.

3. SignalR을 사용하여 채팅방 기능 구현
구현 아이디어를 명확히 한 후 구체적인 구현 코드를 살펴보는 동시에 이전 코드와 비교할 수도 있습니다. 구현 아이디어.
먼저 채팅방 기능과 관련된 엔터티 클래스의 구현 코드를 살펴보세요:

/// <summary>
 /// 用户类
 /// </summary>
 public class User
 {
  /// <summary>
  /// 用户Id
  /// </summary>
  public string UserId { get; set; }
 
  /// <summary>
  /// 用户的连接集合
  /// </summary>
  public List<Connection> Connections { get; set; }
 
  /// <summary>
  /// 用户房间集合,一个用户可以加入多个房间
  /// </summary>
  public List<ChatRoom> Rooms { get; set; }
 
  public User()
  {
   Connections = new List<Connection>();
   Rooms = new List<ChatRoom>();
  }
 }
 
 public class Connection
 {
  //连接ID
  public string ConnectionId { get; set; }
 
  //用户代理
  public string UserAgent { get; set; }
  //是否连接
  public bool Connected { get; set; }
 }
 
  /// <summary>
 /// 房间类
 /// </summary>
 public class ChatRoom
 {
  // 房间名称
  public string RoomName { get; set; }
 
  // 用户集合
  public List<User> Users { get; set; }
 
  public ChatRoom()
  {
   Users = new List<User>();
  }
 }
 
 /// <summary>
 /// 上下文类,用来模拟EF中的DbContext
 /// </summary>
 public class ChatContext
 {
  public List<User> Users { get; set; }
 
  public List<Connection> Connections { get; set; }
 
  public List<ChatRoom> Rooms { get; set; }
 
  public ChatContext()
  {
   Users = new List<User>();
   Connections = new List<Connection>();
   Rooms = new List<ChatRoom>();
  }
 }



2. 다음 , 허브 구현을 살펴보겠습니다.

[HubName("chatRoomHub")]
 public class GroupsHub : Hub
 {
  public static ChatContext DbContext = new ChatContext();
 
  #region IHub Members
  // 重写Hub连接事件
  public override Task OnConnected()
  {
   // 查询用户
   var user = DbContext.Users.FirstOrDefault(u => u.UserId == Context.ConnectionId);
 
   if (user == null)
   {
    user = new User
    {
     UserId = Context.ConnectionId
    };
 
    DbContext.Users.Add(user);
   }
 
   // 发送房间列表
   var items = DbContext.Rooms.Select(p => new {p.RoomName});
   Clients.Client(this.Context.ConnectionId).getRoomList(JsonHelper.ToJsonString(items.ToList()));
   return base.OnConnected();
  }
 
  // 重写Hub连接断开的事件
  public override Task OnDisconnected(bool stopCalled)
  {
   // 查询用户
   var user = DbContext.Users.FirstOrDefault(u => u.UserId == Context.ConnectionId);
 
   if (user != null)
   {
    // 删除用户
    DbContext.Users.Remove(user);
 
    // 从房间中移除用户
    foreach (var item in user.Rooms)
    {
     RemoveUserFromRoom(item.RoomName);
    }
   }
   return base.OnDisconnected(stopCalled);
  }
 
  #endregion
 
  #region Public Methods
 
  // 为所有用户更新房间列表
  public void UpdateRoomList()
  {
   var itme = DbContext.Rooms.Select(p => new {p.RoomName});
   var jsondata = JsonHelper.ToJsonString(itme.ToList());
   Clients.All.getRoomlist(jsondata);
  }
 
  /// <summary>
  /// 加入聊天室
  /// </summary>
  public void JoinRoom(string roomName)
  {
   // 查询聊天室
   var room = DbContext.Rooms.Find(p => p.RoomName == roomName);
 
   // 存在则加入
   if (room == null) return;
 
   // 查找房间中是否存在此用户
   var isExistUser = room.Users.FirstOrDefault(u => u.UserId == Context.ConnectionId);
 
   // 不存在则加入
   if (isExistUser == null)
   {
    var user = DbContext.Users.Find(u => u.UserId == Context.ConnectionId);
    user.Rooms.Add(room);
    room.Users.Add(user);
     
    // 将客户端的连接ID加入到组里面
    Groups.Add(Context.ConnectionId, roomName);
 
    //调用此连接用户的本地JS(显示房间)
    Clients.Client(Context.ConnectionId).joinRoom(roomName);
   }
   else
   {
    Clients.Client(Context.ConnectionId).showMessage("请勿重复加入房间!");
   }
  }
 
  /// <summary>
  /// 创建聊天室
  /// </summary>
  /// <param name="roomName"></param>
  public void CreateRoom(string roomName)
  {
   var room = DbContext.Rooms.Find(a => a.RoomName == roomName);
   if (room == null)
   {
    var cr = new ChatRoom
    {
     RoomName = roomName
    };
 
    //将房间加入列表
    DbContext.Rooms.Add(cr);
 
    // 本人加入聊天室
    JoinRoom(roomName);
    UpdateRoomList();
   }
   else
   {
    Clients.Client(Context.ConnectionId).showMessage("房间名重复!");
   }
  }
 
  public void RemoveUserFromRoom(string roomName)
  {
   //查找房间是否存在
   var room = DbContext.Rooms.Find(a => a.RoomName == roomName);
 
   //存在则进入删除
   if (room == null)
   {
    Clients.Client(Context.ConnectionId).showMessage("房间名不存在!");
    return;
   }
 
   // 查找要删除的用户
   var user = room.Users.FirstOrDefault(a => a.UserId == Context.ConnectionId);
   // 移除此用户
   room.Users.Remove(user);
   //如果房间人数为0,则删除房间
   if (room.Users.Count <= 0)
   {
    DbContext.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)
  {
   // 调用房间内所有客户端的sendMessage方法
   // 因为在加入房间的时候,已经将客户端的ConnectionId添加到Groups对象中了,所有可以根据房间名找到房间内的所有连接Id
   // 其实我们也可以自己实现Group方法,我们只需要用List记录所有加入房间的ConnectionId
   // 然后调用Clients.Clients(connectionIdList),参数为我们记录的连接Id数组。
   Clients.Group(room, new string[0]).sendMessage(room, message + " " + DateTime.Now);
  }
  #endregion
}



3. 위 SignalR 서버의 코드 구현이 완료되었습니다. 다음으로 클라이언트 뷰 구현을 살펴보겠습니다.

@{
 Layout = null;
}
 
<!DOCTYPE html>
 
<html>
<head>
 <meta name="viewport" content="width=device-width" />
 <title>Index</title>
 <script src="~/Scripts/jquery-2.2.2.min.js"></script>
 <script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script>
 <script src="~/Scripts/layer/layer.min.js"></script>
 <!--这里要注意,这是虚拟目录,也就是你在OWIN Startup中注册的地址-->
 <script src="/signalr/hubs"></script>
 
 <script type="text/javascript">
  var chat;
  var roomcount = 0;
   
  $(function() {
   chat = $.connection.chatRoomHub;
   chat.client.showMessage = function(message) {
    alert(message);
   };
   chat.client.sendMessage = function(roomname, message) {
    $("#" + roomname).find("ul").each(function() {
     $(this).append(&#39;<li>&#39; + message + &#39;</li>&#39;);
    });
   };
   chat.client.removeRoom = function(data) {
    alert(data);
   };
   chat.client.joinRoom = function (roomname) {
    var html = &#39;<p style="float:left; margin-left:360px; border:double; height:528px;width:493px" id="&#39; + roomname + &#39;" roomname="&#39; + roomname + &#39;"><button onclick="RemoveRoom(this)">退出</button>\
         &#39; + roomname + &#39;房间\
            聊天记录如下:<ul>\
            </ul>\
         <textarea class="ChatCore_write" id="ChatCore_write" style="width:400px"></textarea> <button onclick="SendMessage(this)">发送</button>\
         </p>&#39;;
    $("#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 = &#39; <li>房间名:&#39; + jsondata[i].RoomName + &#39;<button roomname="&#39; + jsondata[i].RoomName + &#39;" onclick="AddRoom(this)">加入</button></li>&#39;;
      $("#roomlist").append(html);
     }
    }
   };
   // 获取用户名称。
   $(&#39;#username&#39;).html(prompt(&#39;请输入您的名称:&#39;, &#39;&#39;));
 
   $.connection.hub.start().done(function() {
    $(&#39;#CreatRoom&#39;).click(function() {
     chat.server.createRoom($("#Roomname").val());
    });
   });
  });
   
  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);
   $(btn).prev().val(&#39;&#39;).focus();
  }
   
  function RemoveRoom(btn) {
   var room = $(btn).parent();
   var roomname = $(room).attr("roomname");
   chat.server.removeUserFromRoom(roomname);
  }
   
  function AddRoom(roomname) {
   var data =$(roomname).attr("roomname");
   chat.server.joinRoom(data);
  }
 
 </script>
</head>
<body>
 <p>
  <p>名称:<p id="username"></p></p>
  输入房间名:
  <input type="text" value="聊天室1" id="Roomname" />
  <button id="CreatRoom">创建聊天室</button>
 </p>
 <p style="float:left;border:double">
  <p>房间列表</p>
  <ul id="roomlist"></ul>
 </p>
 <p id="RoomList">
 </p>
</body>
</html>


4. 룸 기능이 완료되면 구체적인 효과를 살펴보기 전에 다음과 같은 도우미 코드가 있습니다.

/// <summary>
 /// JSON 帮助类
 /// </summary>
 public class JsonHelper
 {
  /// <summary>
  /// 从一个对象信息生成Json字符串
  /// </summary>
  /// <param name="obj"></param>
  /// <returns></returns>
  public static string ToJsonString(object obj)
  {
   return JsonConvert.SerializeObject(obj);
  }
 
  /// <summary>
  /// 从Json字符串生成对象
  /// </summary>
  /// <typeparam name="T"></typeparam>
  /// <param name="jsonString"></param>
  /// <returns></returns>
  public static T ToObject<T>(string jsonString)
  {
   return JsonConvert.DeserializeObject<T>(jsonString);
  }
 }


4. 실행 결과

다음으로 채팅방 기능의 작동 효과를 자세히 살펴보겠습니다. 구체적인 작동 효과는 아래 그림과 같습니다.

Asp.net은 SignalR을 사용하여 채팅방 기능을 구현합니다.

이제 모든 본 글의 내용은 소개되었습니다. 다음은 SignalR을 사용하여 사진 전송 기능을 구현하는 방법을 구현하는 글입니다.

SignalR을 사용하여 채팅방 기능을 구현하는 Asp.net과 관련된 더 많은 기사를 보려면 PHP 중국어 웹사이트를 주목하세요!


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.