ASP.NET Core2.0使用SignalR和Redis进行实时信息推送

最终效果


ASP.NET Core2.0使用SignalR和Redis进行实时信息推送_第1张图片

ASP.NET Core2.0使用SignalR和Redis进行实时信息推送_第2张图片
下面我只讲解核心代码,因为实现上面效果,还需要很多细节,看完的小伙伴如果有疑问,可以留言。

准备工作和预备知识


首先先用NuGet包下载SignalR包:

Microsoft.AspNetCore.SignalR
StackExchange.Redis

安装过后,需要得就是SignalR的JS文件,这里可以采用npm命令进行安装

npm install @aspnet/signalr

ASP.NET Core2.0使用SignalR和Redis进行实时信息推送_第3张图片
这样,在路径下面就会出现两个文件,一个是node_modules文件夹和package-lock.json文件

ASP.NET Core2.0使用SignalR和Redis进行实时信息推送_第4张图片
我们点进node_modules文件夹的时候,发现有很多文件,但我们只需要一个JS文件就够了
ASP.NET Core2.0使用SignalR和Redis进行实时信息推送_第5张图片
然后把这个js文件导入到我们的项目里面,在ASP.NET Core的Startup文件里的ConfigureServices方法添加一段代码

services.AddSignalR()

在这里插入图片描述
然后在Configure方法里也添加一段代码

            app.UseSignalR(route =>
            {
                route.MapHub("/hubs");
            });

ASP.NET Core2.0使用SignalR和Redis进行实时信息推送_第6张图片
到这里,准备工作就完成了,讲讲预备知识。
在发送信息和接收信息的时候,需要实现的是实时性,即一旦发送人发送了信息,收件人能够立刻收到消息并显示,典型的案例就是聊天室,而实时性又怎么实现呢?大体有三种方式

1.AJAX轮询

此方法是客户端隔一段时间便向服务端请求,询问服务端有没有消息,因为请求大多数是没用的,所以会消耗比较多的资源,

2.长轮询(long polling)

此方法和轮询差不多,不过和轮询的区别在于,发送请求到服务端的时候,服务器端“阻塞”,直到有新消息可以返回的时候,服务端来回响应这个请求,因为请求到服务器,服务端会"阻塞",所以也会消耗一定的资源。

3.WebSocket

WebSocket是HTML5推出的新协议,上面的两种方式中,服务端扮演的被动的角色,即服务端不会主动的告诉客户端有新的消息,而WebSocket解决了这个问题,它实现了双向通讯,服务端可以主动的告诉客户端有消息。具体关于WebSocket可以看看下面的文章。
https://www.zhihu.com/question/20215561

而我们SignalR实现实时性依靠的也是WebSocket,当浏览器支持WebSocket的时候,SignalR就会使用WebSocket来进行交互,如果不支持,则会使用其它方式来实现实时性,即WebSocket在SignalR中是第一优先选择。
到这里,我们准备工作和预备知识就讲完了,下面来看看实现信息推送的流程

简单来说,信息推送的主要思路就是    发    存     读

实现基础:
    和    操作需要实时性,而SignalR可以实现实时性。*
    操作我采用Redis进行存储,关于Redis的讲解,可以参考下面的文章。
https://www.cnblogs.com/yuhangwang/p/5817930.html
采用Redis的原因有两个:
1.读写快速
因为信息是访问频繁而数据量又大的一个东西,如果存储在关系数据库的确可以,但是频繁的取读关系数据库,显得有点浪费性能,而Redis数据库是基于内存的数据库,在读写方面,有着很大的优势
2.Redis的List类型适合存储消息
Redis支持很多类型,String,SortList,List等,其中List类型比较适合我们存放消息。
ASP.NET Core2.0使用SignalR和Redis进行实时信息推送_第7张图片

ASP.NET Core2.0使用SignalR和Redis进行实时信息推送_第8张图片
下面来看看怎么用代码来实现功能。

首先我们要在项目里面创造一个继承于Hub类的继承类(或者说创造一个集线器),它有什么用呢?他减弱了客户端和服务端两个独立物理环境的限界,使得客户端可以调用服务端的方法,服务端可以调用客户端的方法,不过方法只限于集线器中的方法。有关Hub的信息可以看这篇文章
https://www.cnblogs.com/hnsongbiao/p/8716722.html
在这里插入图片描述
重写OnConnectedAsync方法,此方法会在建立WebSocket时调用。
ASP.NET Core2.0使用SignalR和Redis进行实时信息推送_第9张图片

  public override async  Task OnConnectedAsync()
  {     //获取连接ID 
        string id = Context.ConnectionId;
        
        //这里获取用户唯一标识方法不唯一,我这里是通过依赖注入拿到IHttpContextAccessor接口的实现类
        //HttpContextAccessor然后通过Session取出用户唯一标识
        string Name = _httpContextAccessor.HttpContext.Session.GetString("UserName");
           if (Name == null)
           {
                  //只写了简单处理,到时候要用异常处理             
                  return;
            }
            
           //获取用户
           Admin admin = _adminservice.GetAdmin(Name);
           if (admin == null)
          {
                 //只写了简单处理,到时候要用异常处理
                 return;
          }
          
          //将连接用户的ConnectionID和UserID用UserInfo类存储
          UserInfo info = new UserInfo
          {
                  NickName=admin.Name,
                   UserID = admin.ID,
                   ConnectionID = id
          }
                     
          //将用户信息存进Redis
         await _RedisService.SetStringAsync("UserInfo_" + admin.ID, JsonConvert.SerializeObject(info));
         await base.OnConnectedAsync();
                     
  
  }

然后自定义一个发送方法SendMessage给客户端调用

  public async Task SendMessage(string fromNickName,string Name,string Message)
  {
            //收件人的信息
            Admin admin = _adminservice.GetAdmin(Name);
            //发送人的信息
            Admin fromAdmin = _adminservice.GetAdmin(fromNickName);
            
              if (admin == null||fromAdmin==null)
              {
                    //只写了简单处理,到时候要用异常处理
                   return;
              }
            //获取Redis里面用户的连接ID和UserID
            string info = await _RedisService.GetStringAsync("UserInfo_" + admin.ID);
            
             if (info == null)
             {
                  //只写了简单处理,到时候要用异常处理
                   return;
             }
             UserInfo UserInfo =JsonConvert.DeserializeObject(info);
             
             //对收件人发送信息,调用客户端的ReceiveMessage方法
             await Clients.Client(UserInfo.ConnectionID).SendAsync("ReceiveMessage");
             
            //包装要发送的信息
            Info message = new Info()
            {
                 FromNickName = fromNickName,
                 FromUserID = fromAdmin.ID,
                 FromUserMessage = Message,
                 CreateTime = DateTime.Now.ToShortDateString(),
                 status = 0
            }
            
    //将消息加入到Redis
    await _RedisService.InfoLeftPushAsync("Message_" + admin.ID, JsonConvert.SerializeObject(message));
}

上面代码中,出现了RedisService和UserInfo和Info类,RedisService是Redis提供存储,读取服务,UserInfo用来存储用户连接的信息,Info用来存储消息文本

UserInfo类

 public class UserInfo
 {
        public string NickName { get; set; }
        
        public string UserID { get; set; }
        
        public string ConnectionID { get; set; }
        
 }

Info类

 public class Info
 {
      public string FromUserID { get; set; }
      
      public string FromUserMessage { get; set; }
      
      public string CreateTime { get; set; }
      
       public string FromNickName { get; set; }
       
        public int status { get; set; }
      
 }

IRedisService:这里因为我对Redis的封装比较差,就不误人子弟了,这里只提供了接口,具体实现小伙伴可以通过网上其他人对StackExchange.Redis的描述来实现功能。

   public interface IRedisService
   {
        /// 
        /// 设置String类型
        /// 
        /// 
        /// 
        /// 
        Task SetStringAsync(string key, string value);
          
         /// 
        /// 获取String键
        /// 
        /// 
        /// 
        Task GetStringAsync(string key);
         
         /// 
        /// 返回全部信息
        /// 
        /// 
        /// 
        Task> GetInfoAsync(string key);

         /// 
        /// 插入消息进Redis
        /// 
        /// 键
        /// 值
        /// 
        Task InfoLeftPushAsync(string key, string value);
         
          /// 
        /// 获取未读消息数量
        /// 
        /// 用户id
        /// 
        Task GetUnreadInfoCountAsync(string key);

         /// 
        /// 获取未读消息
        /// 
        /// 
        /// 
        Task> GetUnreadInfoAsync(string key);
         
         /// 
        /// 获取已读消息
        /// 
        /// 
        /// 
        Task> GetReadInfoAsync(string key);
      
   }
   

到这里Hub类就完成了,剩下的就是客户端的js代码 ,首先是收件人的核心代码


发送人发送的核心代码


到这里所有代码都写完了,上面的所有代码只是核心代码,还有好多细节代码需要小伙伴实现,这里就不一一给出了,有什么疑问的小伙伴欢迎留言。

你可能感兴趣的:(ASP.NET,Core)