博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Senparc.Weixin.MP SDK 微信公众平台开发教程(七):解决用户上下文(Session)问题...
阅读量:6541 次
发布时间:2019-06-24

本文共 7526 字,大约阅读时间需要 25 分钟。

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

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

    上一篇《》中我们了解到,Senparc.Weixin.MP SDK提供了一套非常便捷的消息处理机制,这套机制上面,我们有增加了一个叫MessageContext的上下文处理机制,下面我们就来说一说这个功能的使用(参考开源项目Wiki中的《》一文)。

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

Senparc.Weixin.MP SDK官方测试微信

 


 

概述

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

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

WeixinContext

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

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

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

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

///       /// 重置所有上下文参数,所有记录将被清空      ///       public void Restore()      {          ...      }      ///       /// 获取MessageContext,如果不存在,返回null      /// 这个方法的更重要意义在于操作TM队列,及时移除过期信息,并将最新活动的对象移到尾部      ///       /// 用户名(OpenId)      /// 
private TM GetMessageContext(string userName) { ... } /// /// 获取MessageContext /// /// 用户名(OpenId) /// True:如果用户不存在,则创建一个实例,并返回这个最新的实例 /// False:用户储存在,则返回null ///
private TM GetMessageContext(string userName, bool createIfNotExists) { ... } /// /// 获取MessageContext,如果不存在,使用requestMessage信息初始化一个,并返回原始实例 /// ///
public TM GetMessageContext(IRequestMessageBase requestMessage) { ... } /// /// 获取MessageContext,如果不存在,使用requestMessage信息初始化一个,并返回原始实例 /// ///
public TM GetMessageContext(IResponseMessageBase responseMessage) { ... } /// /// 记录请求信息 /// /// 请求信息 public void InsertMessage(IRequestMessageBase requestMessage) { ... } /// /// 记录响应信息 /// /// 响应信息 public void InsertMessage(IResponseMessageBase responseMessage) { ... } /// /// 获取最新一条请求数据,如果不存在,则返回Null /// /// 用户名(OpenId) ///
public IRequestMessageBase GetLastRequestMessage(string userName) { ... } /// /// 获取最新一条响应数据,如果不存在,则返回Null /// /// 用户名(OpenId) ///
public IResponseMessageBase GetLastResponseMessage(string userName) { ... }

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

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

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

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

MessageContext

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

///     /// 微信消息上下文(单个用户)接口    ///     /// 
请求消息类型
///
响应消息类型
public interface IMessageContext
where TRequest : IRequestMessageBase where TResponse : IResponseMessageBase { ///
/// 用户名(OpenID) /// string UserName { get; set; } ///
/// 最后一次活动时间(用户主动发送Resquest请求的时间) /// DateTime LastActiveTime { get; set; } ///
/// 接收消息记录 /// MessageContainer
RequestMessages { get; set; } ///
/// 响应消息记录 /// MessageContainer
ResponseMessages { get; set; } ///
/// 最大储存容量(分别针对RequestMessages和ResponseMessages) /// int MaxRecordCount { get; set; } ///
/// 临时储存数据,如用户状态等,出于保持.net 3.5版本,这里暂不使用dynamic /// object StorageData { get; set; } ///
/// 用于覆盖WeixinContext所设置的默认过期时间 /// Double? ExpireMinutes { get; set; } ///
/// AppStore状态,系统属性,请勿操作 /// AppStoreState AppStoreState { get; set; } event EventHandler
> MessageContextRemoved; void OnRemoved(); }

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

///     /// 微信消息上下文(单个用户)    ///     public class MessageContext
: IMessageContext
where TRequest : IRequestMessageBase where TResponse : IResponseMessageBase { private int _maxRecordCount; public string UserName { get; set; } public DateTime LastActiveTime { get; set; } public MessageContainer
RequestMessages { get; set; } public MessageContainer
ResponseMessages { get; set; } public int MaxRecordCount { get { return _maxRecordCount; } set { RequestMessages.MaxRecordCount = value; ResponseMessages.MaxRecordCount = value; _maxRecordCount = value; } } public object StorageData { get; set; } public Double? ExpireMinutes { get; set; } ///
/// AppStore状态,系统属性,请勿操作 /// public AppStoreState AppStoreState { get; set; } public virtual event EventHandler
> MessageContextRemoved = null; ///
/// 执行上下文被移除的事件 /// 注意:此事件不是实时触发的,而是等过期后任意一个人发过来的下一条消息执行之前触发。 /// ///
private void OnMessageContextRemoved(WeixinContextRemovedEventArgs
e) { EventHandler
> temp = MessageContextRemoved; if (temp != null) { temp(this, e); } } ///
/// /// ///
maxRecordCount如果小于等于0,则不限制 public MessageContext(/*MessageContainer
requestMessageContainer, MessageContainer
responseMessageContainer*/) { /* * 注意:即使使用其他类实现IMessageContext, * 也务必在这里进行下面的初始化,尤其是设置当前时间, * 这个时间关系到及时从缓存中移除过期的消息,节约内存使用 */ RequestMessages = new MessageContainer
(MaxRecordCount); ResponseMessages = new MessageContainer
(MaxRecordCount); LastActiveTime = DateTime.Now; } public virtual void OnRemoved() { var onRemovedArg = new WeixinContextRemovedEventArgs
(this); OnMessageContextRemoved(onRemovedArg); } }

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

    上述MessageContext<TRequest,TResponse>类已经提供了比较完备的常用的消息处理的方法,可以直接使用。如果有更加特殊的需求,需要自定义MessageContext,推荐以这个类为基类进行必要的重写,例如下面就是一个自定义的上下文类:

public class CustomMessageContext : MessageContext
{ public CustomMessageContext() { base.MessageContextRemoved += CustomMessageContext_MessageContextRemoved; } ///
/// 当上下文过期,被移除时触发的时间 /// ///
///
void CustomMessageContext_MessageContextRemoved(object sender, Senparc.Weixin.Context.WeixinContextRemovedEventArgs
e) { /* 注意,这个事件不是实时触发的(当然你也可以专门写一个线程监控) * 为了提高效率,根据WeixinContext中的算法,这里的过期消息会在过期后下一条请求执行之前被清除 */ var messageContext = e.MessageContext as CustomMessageContext; if (messageContext == null) { return;//如果是正常的调用,messageContext不会为null } //TODO:这里根据需要执行消息过期时候的逻辑,下面的代码仅供参考 //Log.InfoFormat("{0}的消息上下文已过期",e.OpenId); } }

  上面的CustomMessageContext_MessageContextRemoved()方法会在某个用户的上下文被清除的时候触发,其中可以加入自己需要的代码。除此以外,您也可以重写积累中的OnRemoved()等方法,或者添加其他的属性及方法。

 

 

系列教程索引

地址:

转载地址:http://sbsdo.baihongyu.com/

你可能感兴趣的文章
正确配置jstl的maven依赖,jar包冲突的问题终于解决啦
查看>>
利用KMP算法解决串的模式匹配问题(c++) -- 数据结构
查看>>
登录内网账号后,连接不上内网网址
查看>>
安装 MariaDB
查看>>
【deep learning学习笔记】注释yusugomori的DA代码 --- dA.h
查看>>
Ubuntu 12.04 root用户登录设置
查看>>
windows核心编程-互斥器(Mutexes)
查看>>
纯手工打造漂亮的垂直时间轴,使用最简单的HTML+CSS+JQUERY完成100个版本更新记录的华丽转身!...
查看>>
java 为啥变量名前要加个m?
查看>>
探索Android中的Parcel机制(上)
查看>>
c++ 类型定义
查看>>
C#开发微信门户及应用(5)--用户分组信息管理
查看>>
怎样实现前端裁剪上传图片功能
查看>>
程序员提高工作效率的15个技巧【Facebook】
查看>>
ffmpeg+SDL2实现的视频播放器「退出、暂停、播放」
查看>>
2011/7/3 第二次评审
查看>>
Openvswitch手册(2): OpenFlow Controller
查看>>
tar解压
查看>>
inheritprototype原型继承封装及综合继承最简实例
查看>>
【磁耦隔离接口转换器】系列产品选型指南
查看>>