SignalR中丰富多彩的消息推送方式的实现代码

在上一篇 SignalR 文章中,演示了如何通过 SignalR 实现了简单的聊天室功能;本着简洁就是美的原则,这一篇我们也来聊聊在 SignalR 中的用户和组的概念,理解这些基础知识有助于更好的开发基于 SignalR 的应用,通过对用户和分组的理解,进一步扩展出对用户和分组的管理,以及消息推送的各种方式,为全面接入 SignalR 做准备。

1. 用户

在 SignalR 中,用户表示连接,一个用户代表一个连接,一个“系统用户”可以创建多个连接身份,通过函数集线器,可以给一个用户的所有连接发送消息;比如一个“系统用户”拥有多个连接,这些连接分别是 Web连接、AndroId手机客户端连接,IOS手机客户端连接、或者其它客户端连接,“系统用户”分别登录了这些客户端,同时创建了多个连接;默认情况下这些连接都通过 ClaimTypes.NameIdentifier 在 ClaimsPrincipal 于用户标识进行关联。

** 注意:用户标识符是区分大小写的,为了实现一个客户多个连接,本例还简单实现了一个基于 ClaimsIdentity 登录接口,算是意外惊喜。

1.1 用户连接管理

为了直观的观察到用户是可以拥有多连接的,需要建立一个本地静态对象,用于存储用户连接

public class WeChatHub : Hub
 {
  public Dictionary<string, List<string>> UserList { get; set; } = new Dictionary<string, List<string>>();

  public void Send(ChatMessage body)
  {
   Clients.All.SendAsync("Recv", body);
  }

  public override Task OnConnectedAsync()
  {
   var userName = this.Context.User.Identity.Name;
   var connectionId = this.Context.ConnectionId;
   if (!UserList.ContainsKey(userName))
   {
    UserList[userName] = new List<string>();
    UserList[userName].Add(connectionId);
   }
   else if (!UserList[userName].Contains(connectionId))
   {
    UserList[userName].Add(connectionId);
   }
   Console.WriteLine("哇,有人进来了:{0},{1},{2}", this.Context.UserIdentifier, this.Context.User.Identity.Name, this.Context.ConnectionId);
   return base.OnConnectedAsync();
  }

  public override Task OnDisconnectedAsync(Exception exception)
  {
   var userName = this.Context.User.Identity.Name;
   var connectionId = this.Context.ConnectionId;
   if (UserList.ContainsKey(userName))
   {
    if (UserList[userName].Contains(connectionId))
    {
     UserList[userName].Remove(connectionId);
    }
   }

   Console.WriteLine("靠,有人跑路了:{0}", this.Context.ConnectionId);
   return base.OnDisconnectedAsync(exception);
  }
 }

上面的代码包含了一个内部成员 UserList,用于存储用户的每个连接,在用户进行 SignalR 连接时,将当前连接存储到 UserList 中,当连接断开的时候,将当前连接从 UserList 中删除。这样就实现了一个简单的用户连接管理。

在上面的代码中,当前用户昵称是根据 var userName = this.Context.User.Identity.Name; 这行代码获取的,为了取得这个用户昵称,我们实现了一个简单的 UserIdentity 登录,然后将 User 信息写入到 Cookie 中,最后才可以通过 var userName = this.Context.User.Identity.Name; 获得当前登录用户昵称(熟悉 ID 登录流程的同学应该不会感到陌生,实际上我也很少使用 ID 验证)

1.2 给单个用户发送消息

  [Authorize(Roles = "User")]
  [HttpPost("SendToUser")]
  public async Task<IActionResult> SendToUser([FromBody] UserInfoViewModel model)
  {
   ChatMessage message = new ChatMessage()
   {
    Type = 1,
    Content = model.Content,
    UserName = model.UserName
   };

   if (this.chatHub.UserList.ContainsKey(model.UserName))
   {
    var connections = this.chatHub.UserList[model.UserName].First();
    await this.chatHub.Clients.Client(connections).SendAsync("Recv", new object[] { message });
   }

   return Json(new { Code = 0 });
  }

在 UserController 中,定义了上面的接口 SendToUser ,客户端传入用户昵称和消息,然后服务端就会去根据 ChatHub.UserList 成员查找目标用户的连接信息,最后,通过 SendAsync 将消息推送到目标客户端连接中。

2. 分组

分组的概念类似于聊天室,每个房间就是一个独立的分组,用户可以选择加入 A 房间,也可以选择加入 B 房间,如果业务允许,一个用户还可以加入多个分组(房间),通过使用分组对用户进行管理,可以实现一个或者多个聊天房间,用户可以加入分组,也可以将用户从分组中删除(类似离开房间),这里的用户并发真正意义上的“系统用户”,而是指系统用户创建的那些 SignalR连接。

** 注意:当连接断开后重新发起连接的时候,SignalR 不会保留组成员身份,必须重新加入分组。

下面的代码演示了如何对分组进行操作,要对分组进行操作,主要包含三个方面:

2.1 加入分组

 public async Task AddToGroupAsync(string groupName)
  {
   await Groups.AddToGroupAsync(this.Context.ConnectionId, groupName);
  }

2.2 离开分组

 public async Task RemoveFromGroupAsync(string groupName)
  {
   await Groups.RemoveFromGroupAsync(this.Context.ConnectionId, groupName);
  }

2.3 发送消息到指定分组

 public async Task SendToGroupAsync(string groupName, ChatMessage message)
  {
   await Clients.Group(groupName).SendAsync(groupName, new object[] { message });
  }

对分组的操作非常的简单,几乎都是一行代码的事情,不得不说,微软的封装实在是太好了。

3. SignalR的推送消息的其它方式

通过上面对用户和分组的学习,再去扩展学习其它推送消息的方式,就非常的好理解和上手,在 SignalR 内部还有多种推送消息的方式,他们分别是

3.1 All(全站推送)

3.2 Others(全站推送排除自己)

3.3 OthersInGroup(指定分组推送,排除自己)

3.4 AllExcept(除指定列表外的所有人)

3.5 演示代码

 List<string> blackList = new List<string>();
  public async Task OtherSendAsync(ChatMessage body)
  {
   // 给当前连接到 Hub 上的所有连接发送消息,相当于广播
   await Clients.All.SendAsync("Recv", body);

   // 给当前连接对象发送消息
   await Clients.Caller.SendAsync("Recv", body);

   // 给其它所有连接的客户端发送消息,除了当前正在连接的客户端
   await Clients.Others.SendAsync("Recv", body);

   // 查找当前所有连接的客户端(排除自己),如果是已加入此分组,则给他们推送消息
   await Clients.OthersInGroup("groupName").SendAsync("Recv", body);

   // 给除了 blackList(黑名单)之外的所有人发送消息
   await Clients.AllExcept(blackList).SendAsync("Recv", body);
  }

4. 一个简单的示例

本示例代码包含两个简单的界面

4.1 登录

4.2 各种方式发送消息

结束语

最近在做一个开源项目,还处于试用阶段,准备写个使用的 WIKI 出来,看看大家是否感兴趣,此 SingalR 系列只能不定期更新了,抱歉。

演示代码下载

已托管到 GitHub 仓库

https://github.com/lianggx/Examples/tree/master/SignalR/Ron.SignalRLesson2

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 基于SignalR的消息推送与二维码扫描登录实现代码

    1 概要说明 使用微信扫描登录相信大家都不会陌生吧,二维码与手机结合产生了不同应用场景,基于二维码的应用更是比较广泛.为了满足ios.android客户端与web短信平台的结合,特开发了基于SinglarR消息推送机制的扫描登录.本系统涉及到以下知识点: SignalR:http://signalr.net/ 这官网,ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程.实时 Web 功能是指这样一种功能:当所连接的

  • SignalR Self Host+MVC等多端消息推送服务(二)

    一.概述 上次的文章中我们简单的实现了SignalR自托管的服务端,今天我们来实现控制台程序调用SignalR服务端来实现推送信息,由于之前我们是打算做审批消息推送,所以我们的demo方向是做指定人发送信息,至于做聊天消息和全局广播,这里就不在进行演示了. 二.创建控制台客户端 1.在SignalRProject解决方案下新建一个名为Clinet的控制台 2.在程序包管理控制台中输入以下命令 Install-Package Microsoft.AspNet.SignalR.Client 3.修改

  • SignalR Self Host+MVC等多端消息推送服务(一)

    一.概述 由于项目需要,最近公司项目里有个模块功能,需要使用到即时获得审批通知:原本的设计方案是使用ajax对服务器进行定时轮询查询,刚刚开始数据量和使用量不大的时候还好,后来使用量的增加和系统中各种业务的复杂度增加,服务器的压力也越来越大,于是我想使用消息推送的方式替换掉ajax轮询查询,当有审批提交时,调用推送方法,将消息推送到下一审批人那,这样就减低了服务器的压力. Signal 是微软支持的一个运行在.NET平台上的 html websocket 框架.它出现的主要目的是实现服务器主动推

  • SignalR Self Host+MVC等多端消息推送服务(三)

    一.概述 最近项目确实太忙,而且身体也有点不舒服,慢性咽炎犯了,昨晚睡觉时喘不过气来,一直没休息好,也没什么时间写博客,今天朋友问我什么时候能出web端的消息发送的文章时,我还在忙着改项目的事,趁着中午吃饭和午休的时间,赶紧补上之前欠下的文章. 这章主要是实现多端消息相互通信的简单demo,mvc的web端发送信息到control端等. 二.创建web客户端 1.新建一个WebClient解决方案 2.在WebClient解决方案下新建一个名为Clinet mvc项目 3.根据自己实际情况选择对

  • SignalR中丰富多彩的消息推送方式的实现代码

    在上一篇 SignalR 文章中,演示了如何通过 SignalR 实现了简单的聊天室功能:本着简洁就是美的原则,这一篇我们也来聊聊在 SignalR 中的用户和组的概念,理解这些基础知识有助于更好的开发基于 SignalR 的应用,通过对用户和分组的理解,进一步扩展出对用户和分组的管理,以及消息推送的各种方式,为全面接入 SignalR 做准备. 1. 用户 在 SignalR 中,用户表示连接,一个用户代表一个连接,一个"系统用户"可以创建多个连接身份,通过函数集线器,可以给一个用户

  • 详解Jenkins 实现Gitlab事件自动触发Jenkins构建及钉钉消息推送

    实践环境 GitLab Community Edition 12.6.4 Jenkins 2.284 Post build task 1.9(Jenkins插件) Generic Webhook Trigger Plugin 1.72(Jenkins插件) GitLab 1.5.13(Jenkins插件) 实现步骤 钉钉机器人配置 选择要推送的钉钉群 -> 点击群设置按钮 -> 点击智能群助手 -> 点击添加机器人 -> 点击添加机器人+号按钮 -> 点击自定义->填写

  • java WebSocket实现聊天消息推送功能

    本文实例为大家分享了java WebSocket实现聊天消息推送功能的具体代码,供大家参考,具体内容如下 环境: JDK.1.7.0_51 apache-tomcat-7.0.53 java jar包:tomcat-coyote.jar.tomcat-juli.jar.websocket-api.jar ChatAnnotation消息发送类: import java.io.IOException; import java.util.HashMap; import java.util.Map;

  • Android中使用WebSocket实现群聊和消息推送功能(不使用WebView)

    WebSocket protocol 是HTML5一种新的协议.它实现了浏览器与服务器全双工通信(full-duplex).WebSocket是Web2.0时代的新产物,用于弥补HTTP协议的某些不足,不过他们之间真实的关系是兄弟关系,都是对socket的进一步封装,其目前最直观的表现就是服务器推送和聊天功能.更多知识参考:如何理解 TCP/IP, SPDY, WebSocket 三者之间的关系? 今天的重点是讲如何在Android中脱离WebView使用WebSocket,而不是在Web浏览器

  • Android中利用App实现消息推送机制的代码

    1.消息推送机制 服务器器端需要变被动为主动,通知客户一些开发商认为重要的信息,无论应用程序是否正在运行或者关闭. 我想到了一句话:don't call me,i will call you! qq今天在右下角弹出了一个对话框:"奥巴马宣布本拉登挂了...",正是如此. 自作聪明,就会带点小聪明,有人喜欢就有人讨厌. 2.独立进程 无论程序是否正在运行,我们都要能通知到客户,我们需要一个独立进程的后台服务. 我们需要一个独立进程的后台服务. 在androidmanifest.xml中注

  • Android中使用socket通信实现消息推送的方法详解

    原理 最近用socket写了一个消息推送的demo,在这里和大家分享一下. 主要实现了:一台手机向另外一台手机发送消息,这两台手机可以随时自由发送文本消息进行通信,类似我们常用的QQ. 效果图: 原理:手机通过socket发送消息到服务器,服务器每接收到一条消息之后,都会把这条消息放进一个messageList里面,服务器会不停地检测messageList是否含有消息,如果有的话就会根据messageList里面item的数据,推送到相应的另一端手机上面. 下面简单画了一个图来说明这个原理: 演

  • Java中websocket消息推送的实现代码

    一.服务层 package com.demo.websocket; import java.io.IOException; import java.util.Iterator; import java.util.concurrent.ConcurrentLinkedQueue; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import org.springframew

随机推荐