Maison  >  Article  >  développement back-end  >  Asp.net utilise SignalR pour implémenter les fonctions de salle de discussion

Asp.net utilise SignalR pour implémenter les fonctions de salle de discussion

高洛峰
高洛峰original
2016-12-24 14:20:381958parcourir

1. Introduction
Dans l'article précédent "Asp.net utilise SignalR pour implémenter une fonction de chat de bout en bout", je vous ai présenté comment implémenter la fonction de chat de bout en bout. Dans cet article, nous verrons comment utiliser SignalR pour implémenter des fonctions telles que le chat de groupe.

2. Idées de mise en œuvre
Pour implémenter la fonction de discussion de groupe, nous devons d'abord créer une salle, puis chaque utilisateur en ligne peut rejoindre cette salle pour une discussion de groupe. Nous pouvons définir un nom d'utilisateur unique pour la salle. . Le nom sert d'identifiant. Existe-t-il une telle méthode existante dans la bibliothèque de classes SignalR ? La réponse est oui.

// 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


Le code ci-dessus est la méthode principale de mise en œuvre du chat de groupe. Pour le dire franchement, l'objet Groups n'est qu'un objet liste maintenu par la bibliothèque de classes SignalR. En fait, nous pouvons gérer nous-mêmes un objet Dictionary> nom et entrez dans la salle. Le ConnectionId du client est ajouté à ce dictionnaire, puis en cliquant pour envoyer un message dans la salle de discussion, nous trouvons tous les ConnectionIds qui rejoignent la discussion de groupe en fonction du nom de la salle, puis appelons le Méthode Clients.Clients(IList connectionIds) pour envoyer le message Broadcast à chaque client. Ce qui précède est le principe de mise en œuvre d’un salon de discussion.

3. Utilisez SignalR pour implémenter la fonction de salle de discussion
Après avoir clarifié les idées d'implémentation, examinons le code d'implémentation spécifique. En même temps, vous pouvez également comparer le code pour comparer le précédent. idées de mise en œuvre.
Regardez d'abord le code d'implémentation de la classe d'entité impliquée dans la fonction de salon de discussion :

/// <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. Suivant , Voyons l'implémentation du hub :

[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 L'implémentation du code du serveur SignalR ci-dessus est terminée. . Examinons ensuite la mise en œuvre de la vue client :

@{
 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. la fonction de la pièce est terminée. Avant d'examiner les effets spécifiques, voici un code d'aide :

/// <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. Résultats d'exécution

Ensuite, examinons en détail l'effet opérationnel de la fonction de salon de discussion. L'effet opérationnel spécifique est illustré dans la figure ci-dessous :

Asp.net utilise SignalR pour implémenter les fonctions de salle de discussion

À ce stade, tout le contenu de cet article a été présenté. Ensuite, je vais mettre en œuvre un article sur la façon d'utiliser SignalR pour réaliser la fonction d'envoi d'images.

Pour plus d'articles liés à Asp.net utilisant SignalR pour implémenter les fonctions de salle de discussion, veuillez faire attention au site Web PHP chinois !


Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn