溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

微信公眾平臺(tái)開發(fā)之如何解決用戶上下文Session的問題

發(fā)布時(shí)間:2021-09-10 11:39:46 來源:億速云 閱讀:106 作者:小新 欄目:移動(dòng)開發(fā)

這篇文章給大家分享的是有關(guān)微信公眾平臺(tái)開發(fā)之如何解決用戶上下文Session的問題的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過來看看吧。

概述

由于微信公眾平臺(tái)的特殊機(jī)制,所有的信息都由微信服務(wù)器轉(zhuǎn)發(fā)而來,因此服務(wù)器是無法使用Session對(duì)用戶會(huì)話的上下文進(jìn)行管理的。

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

WeixinContext

WeixinContext是所有單個(gè)用戶上下文(MessageContext)實(shí)體的容器(暫且稱為全局上下文)。WeixinContext本身不是靜態(tài)類,意味著您可以在同一個(gè)應(yīng)用中創(chuàng)建多個(gè)上下文實(shí)體。

同時(shí),一個(gè)靜態(tài)的WeixinContext實(shí)例被放入到MessageHandler<TM>中,因此所有項(xiàng)目中由MessageHandler<TM>派生的子類中的WeixinContext是唯一的、全局的(注:TM為實(shí)現(xiàn)IMessageContext的類,包括SDK中已經(jīng)提供的MessageContext)。

因此我們?cè)谌魏我粋€(gè)實(shí)現(xiàn)了MessageHandler<TM>的實(shí)例中(比如叫MyMessageHandler),都可以訪問到一個(gè)類型和名稱都叫WeixinContext的對(duì)象。

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

/// <summary>
     /// 重置所有上下文參數(shù),所有記錄將被清空
     /// </summary>
     public void Restore()
     {
         ...
     }

     /// <summary>
     /// 獲取MessageContext,如果不存在,返回null
     /// 這個(gè)方法的更重要意義在于操作TM隊(duì)列,及時(shí)移除過期信息,并將最新活動(dòng)的對(duì)象移到尾部
     /// </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:如果用戶不存在,則創(chuàng)建一個(gè)實(shí)例,并返回這個(gè)最新的實(shí)例
     /// False:用戶儲(chǔ)存在,則返回null</param>
     /// <returns></returns>
     private TM GetMessageContext(string userName, bool createIfNotExists)
     {
         ...
     }


     /// <summary>
     /// 獲取MessageContext,如果不存在,使用requestMessage信息初始化一個(gè),并返回原始實(shí)例
     /// </summary>
     /// <returns></returns>
     public TM GetMessageContext(IRequestMessageBase requestMessage)
     {
         ...
     }

     /// <summary>
     /// 獲取MessageContext,如果不存在,使用requestMessage信息初始化一個(gè),并返回原始實(shí)例
     /// </summary>
     /// <returns></returns>
     public TM GetMessageContext(IResponseMessageBase responseMessage)
     {
         ...
     }

     /// <summary>
     /// 記錄請(qǐng)求信息
     /// </summary>
     /// <param name="requestMessage">請(qǐng)求信息</param>
     public void InsertMessage(IRequestMessageBase requestMessage)
     {
         ...
     }

     /// <summary>
     /// 記錄響應(yīng)信息
     /// </summary>
     /// <param name="responseMessage">響應(yīng)信息</param>
     public void InsertMessage(IResponseMessageBase responseMessage)
     {
         ...
     }

     /// <summary>
     /// 獲取最新一條請(qǐng)求數(shù)據(jù),如果不存在,則返回Null
     /// </summary>
     /// <param name="userName">用戶名(OpenId)</param>
     /// <returns></returns>
     public IRequestMessageBase GetLastRequestMessage(string userName)
     {
         ...
     }

     /// <summary>
     /// 獲取最新一條響應(yīng)數(shù)據(jù),如果不存在,則返回Null
     /// </summary>
     /// <param name="userName">用戶名(OpenId)</param>
     /// <returns></returns>
     public IResponseMessageBase GetLastResponseMessage(string userName)
     {
         ...
     }

WeixinContext中有兩個(gè)用于儲(chǔ)存用戶上下文的對(duì)象:MessageCollection及MessageQueue。

這兩個(gè)對(duì)象中的元素集合是重合的,但是MessageQueue對(duì)元素進(jìn)行了排序,以便及時(shí)處理掉頂部過期的上下文。

ExpireMinutes用于定義上下文時(shí)間有效期,默認(rèn)為90分鐘??梢栽诔绦虻娜魏蔚胤皆O(shè)置設(shè)個(gè)參數(shù),且立即生效。

PS:MessageQueue中刪除過期數(shù)據(jù)的邏輯以極高的效率運(yùn)作,常規(guī)開發(fā)時(shí)無需考慮CPU占用及對(duì)象沖突的問題(額外校驗(yàn)時(shí)間是否超時(shí))。

MessageContext

MessageContext用于保存單個(gè)用戶的上下文信息,被儲(chǔ)存在WeixinContext的MessageCollection及MessageQueue對(duì)象中。 IMessageContext定義如下:

/// <summary>
/// 微信消息上下文(單個(gè)用戶)接口
/// </summary>
/// <typeparam name="TRequest">請(qǐng)求消息類型</typeparam>
/// <typeparam name="TResponse">響應(yīng)消息類型</typeparam>
public interface IMessageContext<TRequest,TResponse>
    where TRequest : IRequestMessageBase
    where TResponse : IResponseMessageBase
{
    /// <summary>
    /// 用戶名(OpenID)
    /// </summary>
    string UserName { get; set; }
    /// <summary>
    /// 最后一次活動(dòng)時(shí)間(用戶主動(dòng)發(fā)送Resquest請(qǐng)求的時(shí)間)
    /// </summary>
    DateTime LastActiveTime { get; set; }
    /// <summary>
    /// 接收消息記錄
    /// </summary>
    MessageContainer<TRequest> RequestMessages { get; set; }
    /// <summary>
    /// 響應(yīng)消息記錄
    /// </summary>
    MessageContainer<TResponse> ResponseMessages { get; set; }
    /// <summary>
    /// 最大儲(chǔ)存容量(分別針對(duì)RequestMessages和ResponseMessages)
    /// </summary>
    int MaxRecordCount { get; set; }
    /// <summary>
    /// 臨時(shí)儲(chǔ)存數(shù)據(jù),如用戶狀態(tài)等,出于保持.net 3.5版本,這里暫不使用dynamic
    /// </summary>
    object StorageData { get; set; }
 
    /// <summary>
    /// 用于覆蓋WeixinContext所設(shè)置的默認(rèn)過期時(shí)間
    /// </summary>
    Double? ExpireMinutes { get; set; }
 
    /// <summary>
    /// AppStore狀態(tài),系統(tǒng)屬性,請(qǐng)勿操作
    /// </summary>
    AppStoreState AppStoreState { get; set; }
 
    event EventHandler<WeixinContextRemovedEventArgs<TRequest, TResponse>> MessageContextRemoved;
 
    void OnRemoved();
}

 您可以根據(jù)自己的需要?jiǎng)?chuàng)建自己的類,實(shí)現(xiàn)這個(gè)接口,并且被WeixinContext使用。當(dāng)然如果你的要求不是那么特殊,而且你比較懶的話,SDK提供了一個(gè)默認(rèn)的MessageContext實(shí)現(xiàn):

/// <summary>
/// 微信消息上下文(單個(gè)用戶)
/// </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狀態(tài),系統(tǒng)屬性,請(qǐng)勿操作
    /// </summary>
    public AppStoreState AppStoreState { get; set; }
 
    public virtual event EventHandler<WeixinContextRemovedEventArgs<TRequest, TResponse>> MessageContextRemoved = null;
 
    /// <summary>
    /// 執(zhí)行上下文被移除的事件
    /// 注意:此事件不是實(shí)時(shí)觸發(fā)的,而是等過期后任意一個(gè)人發(fā)過來的下一條消息執(zhí)行之前觸發(fā)。
    /// </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*/)
    {
        /*
         * 注意:即使使用其他類實(shí)現(xiàn)IMessageContext,
         * 也務(wù)必在這里進(jìn)行下面的初始化,尤其是設(shè)置當(dāng)前時(shí)間,
         * 這個(gè)時(shí)間關(guān)系到及時(shí)從緩存中移除過期的消息,節(jié)約內(nèi)存使用
         */
 
        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);
    }
}

上面的代碼根據(jù)注釋很好理解,需要說明一下的是StorageData。這是一個(gè)用于儲(chǔ)存任何和用戶上下文有關(guān)數(shù)據(jù)的容器,WeixinContext和IMessageContext沒有對(duì)它進(jìn)行任何引用,完全由開發(fā)者決定里面的內(nèi)容(比如用戶執(zhí)行到哪一步、或某個(gè)比較重要的位置信息等等),類似于Session的作用。

上述MessageContext<TRequest,TResponse>類已經(jīng)提供了比較完備的常用的消息處理的方法,可以直接使用。如果有更加特殊的需求,需要自定義MessageContext,推薦以這個(gè)類為基類進(jìn)行必要的重寫,例如下面就是一個(gè)自定義的上下文類:

public class CustomMessageContext : MessageContext<IRequestMessageBase,IResponseMessageBase>
{
    public CustomMessageContext()
    {
        base.MessageContextRemoved += CustomMessageContext_MessageContextRemoved;
    }
 
    /// <summary>
    /// 當(dāng)上下文過期,被移除時(shí)觸發(fā)的時(shí)間
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void CustomMessageContext_MessageContextRemoved(object sender, Senparc.Weixin.Context.WeixinContextRemovedEventArgs<IRequestMessageBase,IResponseMessageBase> e)
    {
        /* 注意,這個(gè)事件不是實(shí)時(shí)觸發(fā)的(當(dāng)然你也可以專門寫一個(gè)線程監(jiān)控)
         * 為了提高效率,根據(jù)WeixinContext中的算法,這里的過期消息會(huì)在過期后下一條請(qǐng)求執(zhí)行之前被清除
         */
 
        var messageContext = e.MessageContext as CustomMessageContext;
        if (messageContext == null)
        {
            return;//如果是正常的調(diào)用,messageContext不會(huì)為null
        }
 
        //TODO:這里根據(jù)需要執(zhí)行消息過期時(shí)候的邏輯,下面的代碼僅供參考
 
        //Log.InfoFormat("{0}的消息上下文已過期",e.OpenId);
    }
}

上面的CustomMessageContext_MessageContextRemoved()方法會(huì)在某個(gè)用戶的上下文被清除的時(shí)候觸發(fā),其中可以加入自己需要的代碼。除此以外,您也可以重寫積累中的OnRemoved()等方法,或者添加其他的屬性及方法。

感謝各位的閱讀!關(guān)于“微信公眾平臺(tái)開發(fā)之如何解決用戶上下文Session的問題”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI