在上一篇 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){

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

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

SignalR 中丰富多彩的消息推送方式相关推荐

  1. Worktile中的实时消息推送服务实现

    在团队协同工具worktile的使用过程中,你会发现无论是右上角的消息通知,还是在任务面板中拖动任务,还有用户的在线状态,都是实时刷新.Worktile中的推送服务是采用的是基于xmpp协议.erla ...

  2. Asp.net SignalR 实现服务端消息推送到Web端

    参考博客https://www.cnblogs.com/wintersun/p/4148223.html ASP .NET SignalR是一个ASP .NET 下的类库,可以在ASP .NET 的W ...

  3. App中如何实现消息推送

    转载地址:https://zhuanlan.zhihu.com/p/19801751 如今的手机每天都会被各种App的消息推送覆盖,消息推送也成了周末去哪儿APP增加自己曝光量的一种重要手段.消息推送 ...

  4. 关于web端的消息推送方式转载

    引言: 在互联网高速发展的时代里,web应用大有取代桌面应用的趋势,不必再去繁琐的安装各种软件,只需一款主流浏览器即可完成大部分常规操作,这些原因都在吸引着软件厂商和消费者.而随着各大厂商浏览器版本的 ...

  5. web中的GoEasy消息推送机制

    最近要用到消息推送机制,网上查了很多,什么websocket,pushlet,GoEasy等,最后发现还是GoEasy最简单方便,很容易入手,不到10分钟就可以进行web端的消息推送啦 话不多说,直接 ...

  6. .net 实时通信_基于 RabbitMQ 的实时消息推送

    实现服务器端推送的几种方式 Web 应用都是基于 HTTP 协议的请求/响应模式,无法像 TCP 协议那样保持长连接,因此 Web 应用就很难像手机那样实现实时的消息推送.就目前来看,Web 应用的消 ...

  7. 【Websocket 第三篇】消息推送

    1. 背景 公司内目前有几个项目都有消息推送的功能,例如:某个业务操作之后需要推送消息给前端页面,让用户实时感知. 但是目前公司内的消息推送实现分散在在各个项目中,与业务系统强耦合,如果有其他项目需要 ...

  8. 个推 php ios,消息推送API

    消息推送API 简述 个推为开发者提供了如下3种消息推送方式: toSingle :简称"单推",指向单个用户推送消息 toList:简称"批量推",指向制定的 ...

  9. Android消息推送 解决方案

    前言 鉴于现在运营需求的增强,消息推送在Android开发中应用的场景是十分常见 如电商的活动宣传.资讯类产品进行新闻推送等等 推送消息截图 今天,我将全面介绍Android中实现消息推送的7种主流解 ...

最新文章

  1. 关于 synchronizeOnSession
  2. 【Linux部署】Spring Boot 项目部署在Linux环境下的Docker容器内举例【任务调度系统 xxl-job 任务调度中心】(手动版)
  3. easy-ui的datagrid
  4. 取二维数组最大值_学习Java,你必需要知道这些——Java数组
  5. vue计算属性与监听器的区别
  6. matlab 修正后阿尔法,修正后的阿尔法均值滤波器Alpha.ppt
  7. 小米nfc模拟加密门禁卡详细图文教程(实测可用)----------------- IC ID CUID卡区别
  8. NE555延时电路设计
  9. 计算机毕业设计java+ssm协同过滤推荐算法的电影资源平台(源码+系统+mysql数据库+Lw文档)
  10. java创建无法确定大小的数组
  11. 感悟哪吒的故事,我命由我不由天
  12. 微信公众平台的php文件的,php版微信公众平台入门教程之开发者认证的方法
  13. 使用RMAN恢复备库
  14. SpringSecurity,jwt oathu sso,YeZiJie
  15. sublime 的一个神秘快捷键
  16. @value()注解
  17. 《小岛经济学》一、前言
  18. 华为路由器:IPSec加密GRE通道(GRE over IPsec)
  19. 使 ASP.NET Web 站点易于访问
  20. Java程序员如何查看本机连接过的 WiFi 和密码

热门文章

  1. mac命令行将输出写入文件_如何在Linux中使用命令行将PDF文件转换为可编辑文本...
  2. 正在创建系统还原点_如何使Windows在启动时自动创建系统还原点
  3. 后缀的形容词_构词法(18)构成形容词的常见后缀 3
  4. 去创业公司不能有一夜暴富的侥幸,更不能指望掉馅饼
  5. keepalived 报错 Popt libraries is required
  6. 如何在画面中摆放大量图片
  7. left outer join 和 right outer join 和 join 的区别
  8. Prism For WPF Login对话框又简单又合理的方案之一
  9. 为什么 Dapper 的批量插入比我预期的要慢很多?
  10. NET问答: 如何在 dynamic 集合上使用 Linq ?