Hub的管理

  • 重写OnConnectedAsync

    从连接信息中获取UserId、Groups,ConnectId,并实现这三者的关系,存放于redis中

    代码请查看
    using CTS.Signalr.Server.Cores;
    using CTS.Signalr.Server.Dtos;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.SignalR;
    using Microsoft.Extensions.Logging;
    using System;
    using System.Linq;
    using System.Threading.Tasks; namespace CTS.Signalr.Server.Hubs
    {
    /// <summary>
    /// 服务端接口
    /// </summary>
    public interface IServerNotifyHub
    { } /// <summary>
    /// 客户端使用的接口
    /// </summary>
    public interface IClientNotifyHub
    {
    Task OnNotify(object data); Task OnLine(object data); Task OffLine(object data);
    } [Authorize]
    public class NotifyHub : Hub<IClientNotifyHub>,IServerNotifyHub
    {
    private readonly SignalrRedisHelper _signalrRedisHelper;
    private readonly ILogger _logger; public NotifyHub(SignalrRedisHelper signalrRedisHelper, ILogger<NotifyHub> logger)
    {
    _signalrRedisHelper = signalrRedisHelper;
    _logger = logger;
    } public override async Task OnConnectedAsync()
    {
    //await Clients.All.OnNotify(new { UserId= Context.User.Identity.Name, Name=Context.User.Identity.Name, ConnectId = Context.ConnectionId });
    var userId= Context.User.Identity.Name;
    var groups=Context.GetHttpContext().Request.Query["group"].FirstOrDefault();
    _logger.LogDebug($"OnConnectedAsync----userId:{userId},groups:{groups},connectionId:{ Context.ConnectionId}");
    if (!string.IsNullOrWhiteSpace(userId))
    {
    await _signalrRedisHelper.AddConnectForUserAsync(userId, Context.ConnectionId);
    await JoinToGroup(userId, Context.ConnectionId, groups?.Split(','));
    await DealOnLineNotify(userId, Context.ConnectionId);
    }
    await base.OnConnectedAsync();
    } public override async Task OnDisconnectedAsync(Exception exception)
    {
    var userId = Context.User.Identity.Name;
    var groups = Context.GetHttpContext().Request.Query["group"].FirstOrDefault();
    _logger.LogDebug($"OnDisconnectedAsync----userId:{userId},groups:{groups},connectionId:{ Context.ConnectionId}");
    if (!string.IsNullOrWhiteSpace(userId))
    {
    await _signalrRedisHelper.RemoveConnectForUserAsync(userId, Context.ConnectionId);
    await DealOffLineNotify(userId,Context.ConnectionId);
    }
    await LeaveFromGroup(Context.ConnectionId, groups?.Split(','));
    await base.OnDisconnectedAsync(exception);
    } /// <summary>
    /// 加入组
    /// </summary>
    /// <param name="groupName"></param>
    /// <returns></returns>
    private async Task JoinToGroup(string userId,string connectionId,params string[] groups)
    {
    if (!string.IsNullOrWhiteSpace(userId)&& groups!=null&&groups.Length>0)
    {
    foreach (var group in groups)
    {
    await Groups.AddToGroupAsync(connectionId, group);
    await _signalrRedisHelper.AddUserForGroupAsync(group, connectionId, userId); // await Clients.Group(group).OnJoinGroup(new { ConnectId = connectionId, UserId = userId, GroupName = group });
    }
    }
    } /// <summary>
    /// 从组中移除
    /// </summary>
    /// <param name="groupName"></param>
    /// <returns></returns>
    private async Task LeaveFromGroup(string connectionId,params string[] groups)
    {
    if (groups != null && groups.Length > 0)
    {
    foreach (var group in groups)
    {
    await Groups.RemoveFromGroupAsync(connectionId, group);
    await _signalrRedisHelper.RemoveConnectFromGroupAsync(group,connectionId);
    // await Clients.Group(group).OnLeaveGroup(new { ConnectId = connectionId, GroupName = group });
    }
    }
    } /// <summary>
    /// 处理上线通知(只有用户第一个连接才通知)
    /// </summary>
    /// <param name="userId"></param>
    /// <param name="connectionId"></param>
    /// <returns></returns>
    private async Task DealOnLineNotify(string userId,string connectionId)
    {
    var userConnectCount = await _signalrRedisHelper.GetConnectsCountByUserAsync(userId);
    await Clients.All.OnLine(new OnLineData()
    {
    UserId = userId,
    ConnectionId = connectionId,
    IsFirst = userConnectCount == 1
    });
    } /// <summary>
    /// 处理下线通知(只有当用户一个连接都没了 才算下线)
    /// </summary>
    /// <param name="userId"></param>
    /// <param name="connectionId"></param>
    /// <returns></returns>
    private async Task DealOffLineNotify(string userId,string connectionId)
    {
    var userConnectCount = await _signalrRedisHelper.GetConnectsCountByUserAsync(userId);
    await Clients.All.OffLine(new OffLineData()
    {
    UserId = userId,
    ConnectionId = connectionId,
    IsLast = userConnectCount == 0
    });
    }
    }
    }

提供给业务系统调用的API

  • [POST] api/notify/post

    application/json形式 提交,数据格式如下

    {
    GroupIds:'', // [可空] 组id集合,多个用,隔开
    UserIds:'',// [可空] 用户id集合,多个用,隔开
    ExcludeUsers:boolean, // 是否排除用户列表中的用户
    NotifyObj:Object // 通知的对象,任意类型(总大小不要超过36k)
    }
    • 有GroupIds

      • ExcludeUsers=true

        推送给指定的组中所有用户(排除掉UserIds部分)

      • ExcludeUsers=false

        推送给组中指定(UserIds中指定的)的这些用户

    • 无GroupIds

      • ExcludeUsers=true

        推送给当前所有连接(排除掉UserIds部分的用户)

      • ExcludeUsers=false

        推送给指定用户(UserIds中指定的用户)

  • [POST] api/notify/postConnects

    application/json提交,数据格式如下

    {
    Connects:'', // 连接Id集合,多个用,隔开
    NotifyObj:Object // 通知的对象,任意类型(总大小不要超过36k)
    }
    • 有UserId

      • ExcludeConnectId=true

        给改用户除指定的ConnectId外的所有连接端推送
      • ExcludeConnectId=false

        跟没指定UserId一致
    • 无UserId

      给指定连接Id推送
  • [GET] api/users

    获取在线用户Id列表

  • [GET] api/groups

    获取在线组列表

增加日志记录

为了方便分析和定位问题,使用log4net来作为日志记录器。

  • nuget 安装log4net

    nuget 搜索 log4net,安装
  • Config中配置

    在Config中注入ILoggerFactory,然后使用添加Log4Net,代码如下所示
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHsts(); loggerFactory.AddLog4Net();
...
}
  • 添加log4net配置文件

    更多配置请自行查找log4net官方配置文档
<?xml version="1.0" encoding="utf-8" ?>
<!--LOG4日志级别
0:TRACE;记录一些对程序员调试问题有帮助的信息, 其中可能包含一些敏感信息, 所以应该避免在生产环境中启用Trace日志。
1:DEBUG;记录一些在开发和调试阶段有用的短时变量(Short-term usefulness), 所以除非为了临时排除生产环境的故障,开发人员应该尽量避免在生产环境中启用Debug日志。
2:INFO;信息日志,记录应用程序的一些流程, 例如,记录当前api请求的url,请求参数等。
3:WARN;警告日志;记录应用程序中发生的不正常或者未预期的事件信息。这些信息中可能包含错误消息或者错误产生的条件, 例如, 文件未找到,用户不存在。
4:ERROR;错误日志;记录应用程序中某个操作产生的错误和异常信息,如对空值进行操作等。
5:FATAL;毁灭性错误;记录一些需要立刻修复的问题。例如数据丢失,磁盘空间不足。
trace<debug<info<warn<error<fatal -->
<log4net>
<appender name="ErrorRollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="AppData\\logs\\" />
<appendToFile value="true" />
<rollingStyle value="Date"/>
<datePattern value="yyyy-MM-dd-'error.log'"/>
<maxSizeRollBackups value="100" />
<staticLogFileName value="false" />
<encoding value="utf-8" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5level %date [%-5.5thread] %-40.40logger - %message%newline" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="ERROR" />
<levelMax value="FATAL" />
</filter>
</appender> <root>
<level value="All" />
<appender-ref ref="ErrorRollingFileAppender" />
</root>
</log4net>

至此,log4net配置完毕

更多内容请通过快速导航查看下一篇

快速导航

标题 内容
索引 .net core 3.0 Signalr - 实现一个业务推送系统
上一篇 .net core 3.0 Signalr - 06 业务实现-业务分析
下一篇 .net core 3.0 Signalr - 08 业务实现-客户端demo
源码地址 源码
官方文档 官方文档

.net core 3.0 Signalr - 07 业务实现-服务端 自定义管理组、用户、连接的更多相关文章

  1. .net core 3.0 Signalr - 06 业务实现-业务分析

    ## 业务需求 1. 人-项目关系 一个人可以属于多个项目,一个项目可以有多个人加入,通知的时候,可以通知项目内的所有人,也可以通知部分人或者某个责任人. 2. 登录互斥 同一个人不允许登录两次(不同 ...

  2. .net core 3.0 Signalr - 08 业务实现-客户端demo

    由于signalr作为一个单独的推送系统,跟业务系统是分离开的,所以此处模拟一个业务系统,新建一个.net core app项目 ## 模拟实现一个登录功能 我们的登录很简单,当进入系统,如果检测到用 ...

  3. .net core 3.0 Signalr - 实现一个业务推送系统

    ## 介绍 ASP.NET Core SignalR 是一个开源代码库,它简化了向应用添加实时 Web 功能的过程. 实时 Web 功能使服务器端代码能够即时将内容推送到客户端. SignalR 的适 ...

  4. .net core 3.0 Signalr - 05 使用jwt将用户跟signalr关联

    Signalr是以Group.Connect为核心来进行推送,比如,给某个组.某个连接来推送,但实际场景中,核心应该是某个组.某个人:然而一个人可以对应多个连接(浏览器多个tab页):本节就来介绍下自 ...

  5. .net core 3.0 Signalr - 09 待改进&交流

    ## 个人心得 写博客真的比写代码累,膜拜那些坚持写博客的大佬! 有时候零散的片段比较多,没写之前感觉有千千万万要写的东西,实际写的时候发现, 好像这个没啥说的,然后就帖了个图,或者一笔带过了 ## ...

  6. .net core 3.0 Signalr - 01 基础篇

    因为将signalr作为单独的站点,此处需要建立两个项目,一个专门用于signalr作为推送项目,一个客户端(实际的业务项目) ## 基础知识速览 ### Clients对象属性 | 属性 | 描述 ...

  7. .net core 3.0 Signalr - 02 使用强类型的Hub

    ## 强类型的优缺点 - 优点 强类型的Hub可以避免魔法函数名,相比弱类型更容易维护和发现问题,直接上代码 - 缺点 特么的得多些好几行代码 ## 代码 ### 接口定义 ``` C# /// // ...

  8. .net core 3.0 Signalr - 03 使用MessagePack压缩传输内容

    ## MessagePack基础介绍 Signalr默认使用的是json形式传递数据,但是signalr提供了灵活的扩展,支持MessagePack形式序列化数据,以增加性能降低网络传输的效果,极大的 ...

  9. .net core 3.0 Signalr - 04 使用Redis做底板来支持横向扩展

    在实际的系统中,可能需要多台机器部署;然而,Signalr的连接信息是跟站点走的,举个例子 推送系统部署了A.B两个服务器,张三访问A服务器,李四访问B服务器,当张三通过A服务器向李四推送的时候,A服 ...

随机推荐

  1. Linux 下安装 mysql8

    1.下载mysql wget https://cdn.mysql.com//Downloads/MySQL-8.0/mysql-8.0.13-linux-glibc2.12-x86_64.tar 2. ...

  2. Flink的Job启动TaskManager端(源码分析)

    前面说到了  Flink的JobManager启动(源码分析)  启动了TaskManager 然后  Flink的Job启动JobManager端(源码分析)  说到JobManager会将转化得到 ...

  3. HashMap原理。图文并茂式解读。这些注意点你一定还不了解

    目录 概述 属性详解 table entrySet size modCount threshold.loadFactor 源码知识点必备 getGenericInterfaces和getInterfa ...

  4. Keras(四)CNN 卷积神经网络 RNN 循环神经网络 原理及实例

    CNN 卷积神经网络 卷积 池化 https://www.cnblogs.com/peng8098/p/nlp_16.html 中有介绍 以数据集MNIST构建一个卷积神经网路 from keras. ...

  5. 2019DX#2

    Solved Pro.ID Title Ratio(Accepted / Submitted)   1001 Another Chess Problem 8.33%(1/12)   1002 Beau ...

  6. hdu 1024 Max Sum Plus Plus(简单dp)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=1024 题意:给定一个数组,求其分成m个不相交子段和的最大值. 这题有点问题其实m挺小的但题目并没有给出 ...

  7. hdu 1540 Tunnel Warfare(线段树)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=1540 题意:D代表破坏村庄,R代表修复最后被破坏的那个村庄,Q代表询问包括x在内的最大连续区间是多少. ...

  8. codeforces 361 D. Levko and Array(dp+二分)

    题目链接:http://codeforces.com/contest/361/problem/D 题意:最多可以修改K次数字,每次修改一个数字变成任意值,C=max(a[i+1]-a[i]):求操作之 ...

  9. ets查询接口match、select说明

    ets:match/2用法:match(Tab, Pattern) -> [Match]返回和模式Pattern匹配的对象.一个匹配模式可能包含:绑定部分.'_'匹配任何Erlang项和匹配变量 ...

  10. mysql之innodb存储引擎---BTREE索引实现

    在阅读本篇文章可能需要一些B树和B+树的基础 一.B树和B+树的区别 1.B树的键值不会出现多次,而B+树的键值一定会出现在叶子节点上,而且在非叶子节点也可能会重复出现2.B数存储真实数据,B+数叶子 ...