当前位置: 首页 > news >正文

Senparc.Weixin.MP SDK 微信公众平台开发教程(七):解决用户上下文(Session)问题...

 

    从这篇文章中我们已经了解了微信公众平台消息传递的方式,这种方式有一个先天的缺陷:不同用户的请求都来自同一个微信服务器,这使得常规的Session无法使用(始终面对同一个请求对象,况且还有对方服务器Cookie是否能保存的问题)。

    这就要求我们自己建立一套独立的对话上下文请求机制。

    上一篇《Senparc.Weixin.MP SDK 微信公众平台开发教程(六):了解MessageHandler》中我们了解到,Senparc.Weixin.MP SDK提供了一套非常便捷的消息处理机制,这套机制上面,我们有增加了一个叫MessageContext的上下文处理机制,下面我们就来说一说这个功能的使用(参考开源项目Wiki中的《用户上下文WeixinContext和MessageContext》一文)。

     更多实际应用的代码可以参考开源项目中的Demo:https://github.com/JeffreySu/WeiXinMPSDK,此外您也可以关注下方的微信二维码,不断发送文字及各种信息进行测试(发送文字的时候才能看到完整结果,期间可以发送其他任意类型)。

 

参考网站:http://www.dandanxiaoshuo.com/

 


 

概述

由于微信公众平台的特殊机制,所有的信息都由微信服务器转发而来,因此服务器是无法使用Session对用户会话的上下文进行管理的。

为此Senparc.WeiXin.MP SDK增加了上下文的模块,并集成到了MessageHandler中。

WeixinContext

WeixinContext是所有单个用户上下文(MessageContext)实体的容器(暂且称为全局上下文)。WeixinContext本身不是静态类,意味着您可以在同一个应用中创建多个上下文实体。

同时,一个静态的WeixinContext实例被放入到MessageHandler<TM>中,因此所有项目中由MessageHandler<TM>派生的子类中的WeixinContext是唯一的、全局的(注:TM为实现IMessageContext的类,包括SDK中已经提供的MessageContext)。

因此我们在任何一个实现了MessageHandler<TM>的实例中(比如叫MyMessageHandler),都可以访问到一个类型和名称都叫WeixinContext的对象。

WeixinContext用于保存所用户的上下文(MessageContext),并且提供了一系列的方法,主要方法包括:

      /// <summary>
      /// 重置所有上下文参数,所有记录将被清空
      /// </summary>
      public void Restore()
      {
          ...
      }

      /// <summary>
      /// 获取MessageContext,如果不存在,返回null
      /// 这个方法的更重要意义在于操作TM队列,及时移除过期信息,并将最新活动的对象移到尾部
      /// </summary>
      /// <param name="userName">用户名(OpenId)</param>
      /// <returns></returns>
      private TM GetMessageContext(string userName)
      {
          ...
      }

      /// <summary>
      /// 获取MessageContext
      /// </summary>
      /// <param name="userName">用户名(OpenId)</param>
      /// <param name="createIfNotExists">True:如果用户不存在,则创建一个实例,并返回这个最新的实例
      /// False:用户储存在,则返回null</param>
      /// <returns></returns>
      private TM GetMessageContext(string userName, bool createIfNotExists)
      {
          ...
      }


      /// <summary>
      /// 获取MessageContext,如果不存在,使用requestMessage信息初始化一个,并返回原始实例
      /// </summary>
      /// <returns></returns>
      public TM GetMessageContext(IRequestMessageBase requestMessage)
      {
          ...
      }

      /// <summary>
      /// 获取MessageContext,如果不存在,使用requestMessage信息初始化一个,并返回原始实例
      /// </summary>
      /// <returns></returns>
      public TM GetMessageContext(IResponseMessageBase responseMessage)
      {
          ...
      }

      /// <summary>
      /// 记录请求信息
      /// </summary>
      /// <param name="requestMessage">请求信息</param>
      public void InsertMessage(IRequestMessageBase requestMessage)
      {
          ...
      }

      /// <summary>
      /// 记录响应信息
      /// </summary>
      /// <param name="responseMessage">响应信息</param>
      public void InsertMessage(IResponseMessageBase responseMessage)
      {
          ...
      }

      /// <summary>
      /// 获取最新一条请求数据,如果不存在,则返回Null
      /// </summary>
      /// <param name="userName">用户名(OpenId)</param>
      /// <returns></returns>
      public IRequestMessageBase GetLastRequestMessage(string userName)
      {
          ...
      }

      /// <summary>
      /// 获取最新一条响应数据,如果不存在,则返回Null
      /// </summary>
      /// <param name="userName">用户名(OpenId)</param>
      /// <returns></returns>
      public IResponseMessageBase GetLastResponseMessage(string userName)
      {
          ...
      }

WeixinContext中有两个用于储存用户上下文的对象:MessageCollection及MessageQueue。

这两个对象中的元素集合是重合的,但是MessageQueue对元素进行了排序,以便及时处理掉顶部过期的上下文。

ExpireMinutes用于定义上下文时间有效期,默认为90分钟。可以在程序的任何地方设置设个参数,且立即生效。

PS:MessageQueue中删除过期数据的逻辑以极高的效率运作,开发时无需考虑CPU占用及对象冲突的问题(额外校验时间是否超时)。

MessageContext

MessageContext用于保存单个用户的上下文信息,被储存在WeixinContext的MessageCollection及MessageQueue对象中。 IMessageContext定义如下:

  public interface IMessageContext
  {
      /// <summary>
      /// 用户名(OpenID)
      /// </summary>
      string UserName { get; set; }
      /// <summary>
      /// 最后一次活动时间(用户主动发送Resquest请求的时间)
      /// </summary>
      DateTime LastActiveTime { get; set; }
      /// <summary>
      /// 接收消息记录
      /// </summary>
      List<IRequestMessageBase> RequestMessages { get; set; }
      /// <summary>
      /// 响应消息记录
      /// </summary>
      List<IResponseMessageBase> ResponseMessages { get; set; }
      /// <summary>
      /// 临时储存数据,如用户状态等,出于保持.net 3.5版本,这里暂不使用dynamic
      /// </summary>
      object StorageData { get; set; }
  }

您可以根据自己的需要创建自己的类,实现这个接口,并且被WeixinContext使用。当然如果你的要求不是那么特殊,而且你比较懒的话,SDK提供了一个默认的MessageContext实现:

  /// <summary>
  /// 微信消息上下文(单个用户)
  /// </summary>
  public class MessageContext : IMessageContext
  {
      public string UserName { get; set; }
      public DateTime LastActiveTime { get; set; }
      public List<IRequestMessageBase> RequestMessages { get; set; }
      public List<IResponseMessageBase> ResponseMessages { get; set; }

      public object StorageData { get; set; }

      public MessageContext()
      {
          /*
           * 注意:即使使用其他类实现IMessageContext,
           * 也务必在这里进行下面的初始化,尤其是设置当前时间,
           * 这个时间关系到及时从缓存中移除过期的消息,节约内存使用
           */
          RequestMessages = new List<IRequestMessageBase>();
          ResponseMessages = new List<IResponseMessageBase>();
          LastActiveTime = DateTime.Now;
      }
  }

上面的代码根据注释很好理解,需要说明一下的是StorageData。这是一个用于储存任何和用户上下文有关数据的容器,WeixinContext和IMessageContext没有对它进行任何引用,完全由开发者决定里面的内容(比如用户执行到哪一步、或某个比较重要的位置信息等等),类似于Session的作用。

 

 

      系列教程索引:http://www.cnblogs.com/tianxiang2046/p/3574957.html

转载于:https://www.cnblogs.com/tianxiang2046/p/3574976.html

相关文章:

  • QM课程03-采购中的质量管理
  • win7 wamp 64位 php环境如何开启curl服务?
  • ZOJ3765 Lights Splay树
  • 4个实用的微服务测试策略
  • float,double和decimal类型
  • iOS:高仿闲鱼、京东等列表底部分页视图
  • 使用MDI 和 XtraTabbedMdiManager 后 选项卡切换后Ribbon 合并后不选中MDI子窗...
  • java~springboot~ibatis Invalid bound statement (not found)原因
  • c#正则表达式
  • 解码 | 25 分钟开发分布式架构的转账小程序
  • 删除2018年以前的文件
  • UTF-8编码规则
  • Java 实现阿里云短信
  • Slog80_打包ArthurSlogMarkdownEditor编辑器至mac平台dmg安装包GET!
  • 一个网站同时监听两个端口
  • canvas 五子棋游戏
  • ES学习笔记(10)--ES6中的函数和数组补漏
  • java8 Stream Pipelines 浅析
  • js继承的实现方法
  • js写一个简单的选项卡
  • node入门
  • React Transition Group -- Transition 组件
  • react-native 安卓真机环境搭建
  • Spring Boot快速入门(一):Hello Spring Boot
  • spring学习第二天
  • 高度不固定时垂直居中
  • 好的网址,关于.net 4.0 ,vs 2010
  • 设计模式(12)迭代器模式(讲解+应用)
  • 通信类
  • 主流的CSS水平和垂直居中技术大全
  • 【运维趟坑回忆录 开篇】初入初创, 一脸懵
  • Hibernate主键生成策略及选择
  • Nginx实现动静分离
  • Python 之网络式编程
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • ​中南建设2022年半年报“韧”字当头,经营性现金流持续为正​
  • #pragma data_seg 共享数据区(转)
  • (13)[Xamarin.Android] 不同分辨率下的图片使用概论
  • (32位汇编 五)mov/add/sub/and/or/xor/not
  • (9)YOLO-Pose:使用对象关键点相似性损失增强多人姿态估计的增强版YOLO
  • (pojstep1.3.1)1017(构造法模拟)
  • (顶刊)一个基于分类代理模型的超多目标优化算法
  • (二十五)admin-boot项目之集成消息队列Rabbitmq
  • (附源码)spring boot建达集团公司平台 毕业设计 141538
  • (南京观海微电子)——I3C协议介绍
  • (全部习题答案)研究生英语读写教程基础级教师用书PDF|| 研究生英语读写教程提高级教师用书PDF
  • (深入.Net平台的软件系统分层开发).第一章.上机练习.20170424
  • .[hudsonL@cock.li].mkp勒索病毒数据怎么处理|数据解密恢复
  • .[hudsonL@cock.li].mkp勒索加密数据库完美恢复---惜分飞
  • .net core 微服务_.NET Core 3.0中用 Code-First 方式创建 gRPC 服务与客户端
  • .net php 通信,flash与asp/php/asp.net通信的方法
  • .NET/ASP.NETMVC 深入剖析 Model元数据、HtmlHelper、自定义模板、模板的装饰者模式(二)...
  • /etc/sudoers (root权限管理)
  • @LoadBalanced 和 @RefreshScope 同时使用,负载均衡失效分析
  • [20170713] 无法访问SQL Server