微信公眾平台開發:解決使用者情境(Session)問題

高洛峰
發布: 2017-02-27 13:08:18
原創
3018 人瀏覽過

概述

由於微信公眾平台的特殊機制,所有的資訊都由微信伺服器轉送而來,因此伺服器是無法使用Session對使用者會話的上下文進行管理的。

為此Senparc.WeiXin.MP SDK增加了上下文的模組,並整合到了MessageHandler中。

WeixinContext

WeixinContext是所有單一使用者上下文(MessageContext)實體的容器(暫且稱為全域上下文)。 WeixinContext本身不是靜態類,意味著您可以在同一個應用程式中建立多個上下文實體。

同時,一個靜態的WeixinContext實例被放入到MessageHandler中,因此所有專案中由MessageHandler派生的子類別中的WeixinContext是唯一的、全域的(註:TM為實作IMessageContext的類,包括SDK中已經提供的MessageContext)。

因此我們在任何一個實作了MessageHandler的實例中(例如叫MyMessageHandler),都可以存取到一個類型和名稱都叫WeixinContext的物件。

WeixinContext用於保存所使用者的上下文(MessageContext),並且提供了一系列的方法,主要方法包括:

     ///


     ///
     /// 重設所有情境參數,所有記錄會清除
     /// < ;/summary>  18"{ oid  store #.
         ...
     }

     ///
     ///在於操作TM佇列,及時移除過期訊息,並將最新活動的物件移到尾部
     ///

     //// 使用者名稱( OpenId)
     ///
     private TM GetMessageContext(string  )
   private TM GetMessageContext  
#      ///
     ///
     /// 取得MessageContext
     ///

  &penlt//////edtin> ;/param>
     /// True:如果使用者不存在,則建立一個實例,並傳回這個最新的實例
     /// False:使用者儲存在,則回傳null
     ///
     private TM GetMessageContext( Corring userName, bool createIfNotExist ##      }


     ///
     /// 取得MessageContext,如果不存在,請使用requestMessage資訊初始化一個,並傳回原始實例
 /   ///
     public TM GetMessageContext(IRequestMessageBase requestMessage)
  #     ///      /// 取得MessageContext,如果不存在,使用requestMessage資訊初始化一個,並回傳原始實例
     ////

    1///

    1/// <
     public TM GetMessageContext(IResponseMessageBase responseMessage)
     {
         ...
 ); // 記錄請求資訊
     / //

     /// 要求資訊
     public void InsertMessage(IRequestMessage{ requestMessage) 系統
     }

     ///
     /// 記錄回應資訊
     ///
">回應資訊
     public void InsertMessage(IResponseMessageBase responseMessage)
     {
   ;
/// 取得最新一條請求數據,若不存在,則回傳Null
     ///

     /// 使用者名稱(OpenId)< /param>
     ///
     public IRequestMessageBase GetLastRequestMessage(string  )
   #  
#      // /
     /// 取得最新回應數據,若不存在,則回傳Null
     ///

    ; ;使用者名稱(OpenId)
     ///
     public IResponseMessageBase GetLastRes {Message(stringuser Name ##      }

WeixinContext中有兩個用來儲存使用者上下文的物件:MessageCollection及MessageQueue。

這兩個物件中的元素集合是重疊的,但是MessageQueue對元素進行了排序,以便及時處理掉頂部過期的上下文。

ExpireMinutes用來定義上下文時間有效期,預設為90分鐘。可以在程式的任何地方設定設個參數,且立即生效。

PS:MessageQueue中刪除過期資料的邏輯以極高的效率運作,常規開發時無需考慮CPU佔用及物件衝突的問題(額外校驗時間是否逾時)。

MessageContext

MessageContext用於保存單一使用者的上下文訊息,被儲存在WeixinContext的MessageCollection及MessageQueue物件中。 IMessageContext定義如下:

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

 您可以根據自己的需求創建自己的類,實現這個接口,並且被WeixinContext使用。當然如果你的要求不是那麼特殊,而且你比較懶的話,SDK提供了一個預設的MessageContext實作:

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

上面的程式碼根據註解很好理解,需要說明一下的是StorageData。這是一個用於儲存任何和使用者上下文有關資料的容器,WeixinContext和IMessageContext沒有對它進行任何引用,完全由開發者決定裡面的內容(例如使用者執行到哪一步、或某個比較重要的位置資訊等等),類似Session的作用。

    上述MessageContext類別已經提供了比較完備的常用的訊息處理的方法,可以直接使用。如果有更特別的需求,需要自訂MessageContext,推薦以這個類別為基底類別進行必要的重寫,例如下面就是一個自訂的上下文類別:

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

上面的CustomMessageContext_MessageContextRemoved()方法會在某個使用者的上下文被清除的時候觸發,其中可以加入自己需要的程式碼。除此之外,您也可以重寫累積中的OnRemoved()等方法,或新增其他的屬性及方法。

更多微信公眾平台開發:解決使用者情境(Session)問題相關文章請關注PHP中文網!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!