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
源码地址 源码
官方文档 官方文档