一個還算簡單的微信消息SDK(基於.Net Standard 2.0)

  雖然微信公衆號出現了好久,不過在SDK這件事情上感覺並沒有多少人把它當成一個有技術含量的事情來做,很多SDK做的事情就是一個代碼的堆疊,當然也可能寫的好的並沒有開源出來。所以在某個翻遍Github而無所獲的下午我寫了一個基礎的基於事件的微信消息類,今年初我把它放到了github和開源中國上並逐步完善,這篇文章就是簡單介紹OSS開源系列下的微信消息模塊SDK的使用方式,主要圍繞以下幾個方面分解:

一. 全局介紹

二. 配置管理

三. 框架使用

  1. 框架組成元素

  2. 框架支持的模式

四. 生命週期擴展

五. 常見問題

六. 終極定製

一. 全局介紹

  整個SDK的核心框架代碼部分不超過300行,支持多租戶平臺模式,以及對各類特殊微信消息的擴展性。代碼在 OSS.SnsSdk下的OSS.SnsSdk.Msg.Wx,【開源中國】和【Github】都可以搜到。

  Nuget安裝命令:Install-Package OSS.SnsSdk.Msg.Wx

  調用方式:

  

二. 配置管理

  (示例詳見:WxMsgController.cs)

  1. 通過構造函數傳入,適合單一的應用,這種情況下的配置信息生存週期和當前config實例同步

  2. 通過 SetContext方式 注入,適合多租戶,平臺的方式使用,這個時候配置的生存週期只在當前請求的整個上下文中有效。

三. 框架使用

  首先,框架組成元素(可以直接跳到使用模式,再回過頭來看):

  1. 實體對象,也就是消息體對象,主要分爲:
     a. 接收消息(繼承自 WxBaseRecMsg 的普通消息 和 繼承自 WxBaseRecEventMsg 的事件消息系統默認實現了 六種普通消息和五種事件消息對象,在後邊的使用模式中介紹如何擴展其他對象類型

     b. 回覆消息(繼承自 WxBaseReplyMsg ,主要是響應給微信接口的實體(當前支持六種 + WxNoneReplyMsg)

    除非特殊情況,否則返回消息基本就是這幾種類型。當前可用回覆消息:

    WxTextReplyMsg-回覆文本消息,WxImageReplyMsg-回覆圖片消息,

    WxVoiceReplyMsg-回覆語音消息,WxVideoReplyMsg-回覆視頻消息,

    WxMusicReplyMsg-回覆音頻消息,WxNewsReplyMsg-回覆圖文消息

    WxNoneReplyMsg 表示不需要給對方響應,系統會返回給微信端success 。使用中可以使用 WxNoneReplyMsg.None 默認值。

     c. 消息上下文(WxMsgContext 對象 

    含有 RecMsg 和 ReplyMsg 兩個屬性,也就是上邊的接收消息和回覆消息,方便在生命週期中控制

  2. Handler,消息處理控制類,實現整個消息處理的生命週期和執行調度
      當前系統有 WxMsgBaseHandler 和 WxMsgHandler 兩個,前者作爲基類,實現了生命週期的控制和調度。 後者則實現了系統基礎消息的事件定義(六個普通消息事件 和 五個Event消息事件)

  3. Procesor(WxMsgProcessor<TRecMsg>),消息的具體執行者.
   這個只有在高級定製模式下才會需要用戶自定義

  其次,框架支持的模式

  1. 基礎模式
      系統 WxMsgHandler.cs 默認實現常見的六種普通消息和五種事件消息,只需要重寫(overwrite)對應的以 Process 開頭的方法即可。每個方法的參數對應的都是詳細的消息類型。以文本類型消息舉例:

 

protected override WxBaseReplyMsg ProcessTextMsg(WxTextRecMsg msg)
{
    return WxNoneReplyMsg.None;
}

那麼可以重寫的包含以下方法:

// 處理文本消息
ProcessTextMsg(WxTextRecMsg msg)

// 處理圖像消息
ProcessImageMsg(WxImageRecMsg msg)

// 處理語音消息
ProcessVoiceMsg(WxVoiceRecMsg msg)

// 處理視頻/小視頻消息
ProcessVideoMsg(WxVideoRecMsg msg)

// 處理地理位置消息
ProcessLocationMsg(WxLocationRecMsg msg)

// 處理鏈接消息
ProcessLinkMsg(WxLinkRecMsg msg)

// 處理關注/取消關注事件
ProcessSubscribeEventMsg(WxSubscribeRecEventMsg msg)

// 處理掃描帶參數二維碼事件
ProcessScanEventMsg(WxSubscribeRecEventMsg msg)

// 處理上報地理位置事件
ProcessLocationEventMsg(WxLocationRecEventMsg msg)

// 處理點擊菜單拉取消息時的事件推送
ProcessClickEventMsg(WxClickRecEventMsg msg)

// 處理點擊菜單跳轉鏈接時的事件推送
ProcessViewEventMsg(WxViewRecEventMsg msg)

 

  2. 進階模式

   對於不在基礎實現類型的消息,系統提供注入消息處理委託的模式來處理消息,以一個 test_msg 消息類型注入示例
   a. 定義消息實體: 

public class WxTestRecMsg : WxBaseRecMsg
{
    public string Test { get; set; }
    // 重寫實體實體內部屬性賦值
    protected override void
         FormatPropertiesFromMsg()
    {
       Test = this["Test"];
    }
}

   b. 定義處理委託:

private static WxTextReplyMsg ProcessTestMsg(WxTestRecMsg msg)
{
    return new WxTextReplyMsg()
        { Content = " test_msg 類型消息返回 " };
}

   c. 注入(內含:RegisteEventProcessor方法):

    WxMsgProcessorProvider.RegisteProcessor<WxTextRecMsg>("test_msg", ProcessTestMsg);

   恭喜,你已經完成了新的消息類型處理注入。

  3. 高級模式
   自定義Processor,基礎模式和進階模式中都在內部實現了Processor的調度,這裏依然使用上邊示例:
   a. 定義實體(這裏繼續使用 WxTestRecMsg)

   b. 定義CustomeHandler, 重寫獲取Processor方法

public class CustomeHandler:WxmsgHandler
{
   protected override WxMsgProcessor GetCustomProcessor(string msgType,string eventName,
     IDictionary<string, string> msgInfo) { if (msgType=="test_msg") { return new WxMsgProcessor<WxTestRecMsg>() { // 此委託屬性滿足對性能有要求的同學 // 如果不填則系統默認會通過泛型的 new t() 創建 RecInsCreater=() => new WxTestRecMsg(), // 具體事件處理委託 // 也可以使用上例的 ProcessTestMsg ProcessFunc = msg => WxNoneReplyMsg.None }; } return null; } }

   恭喜,你又完成了高級模式下的定製。

四. 生命週期擴展

 上邊講解了幾種模式主要實現方式,那麼在實際的使用過程中你會遇到消息的重複判斷,對特定消息的轉發等。在系統處理的不同階段,我定義了幾個主要的處理事件,來滿足對消息處理時的全局和局部控制,分別對應在WxMsgBaseHandler的以Execute開頭的虛方法:

 1. Executing(WxMsgContext context),開始執行事件,作爲範圍爲全部消息類型。所有的消息類型都會經過這個事件,然後執行具體消息類型對應的委託,此時 msgContext 中的 ReplyMsg,如果給context中的 ReplyMsg 屬性賦值,則 後邊定義的對應的具體消息委託放棄執行。

  在這個事件中我們可以過濾重複消息,用戶授權驗證等

 2. ExecuteUnknowProcessor(WxBaseRecMsg msg) 未知消息類型事件,作用範圍爲所有未發現對應處理委託的消息類型。在執行具體的事件時,如果當前消息類型未能找到對應的處理委託,則會喚起這個方法,需要注意的是,即使你使用的是 WxMsgHandler ,如果沒有重寫其 實現,或者返回了爲空, 也會觸發此方法

 可以通過這個方法中添加未知類型消息日誌等

 3. ExecuteEnd(WxMsgContext msgContext), 執行結束時調用的方法,作爲範圍爲全部消息類型。具體消息處理委託執行結束,回覆微信響應之前。此時 msgContext 中的 ReplyMsg 不爲空,如果前面執行方法中返回null,在執行此方法之前,會默認賦值 WxNoneReplyMsg.None
   可以在這裏添加全局日誌,None類型的消息轉發客服等。

五. 常見問題

 1. 各模式的適用場景及區別

  基礎模式,此模式已經由系統內部實現,只需要重寫委託方法即可,簡單方便,基本適用大部分的場景

  進階模式,只需要消息類型,和消息處理委託 在程序入口處註冊即可,簡單靈活。
  其適用場景:基本滿足一般的所有定製需求,但消息體的MsgType不能爲空,微信某些特殊事件無法滿足

  高級模式,使用的是子類繼承模式,每個子類都可以實現同一消息類型下不同定製委託
  其適用的場景: 多租戶平臺下針對每種消息類型,不同的平臺等級都有不同的特殊定製實現以及所有特殊的消息事件

  幾種模式的優先級:基礎模式(使用WxMsgHandler時) => 高級模式 => 進階模式
  舉例:如果你同時在高級模式和進階模式下定義了一個消息類型爲"test"的處理實現,系統默認使用高級模式下的實現。如果你的控制類直接繼承了 WxMsgBaseHandler 則 不會進入基礎模式

 2. 對象屬性的賦值問題

  如果你自定義了接收消息實體的對象,需要重寫FormatPropertiesFromMsg方法,詳見 進階模式下 2.a 的實現。
  對應響應的消息,不需要在執行委託裏給 ToUserName,FromUserName,CreateTime 賦值,系統自動處理。

 3. 使用反射的地方

  爲了儘可能減少系統底層給帶來的性能影響,所以在系統中基本沒有使用反射和序列化,有兩個地方需要注意一下:

  1. 需要在 FormatPropertiesFromMsg 中給自己的屬性賦值,系統儘可能的提供了this索引來簡化賦值的方式。
  2. 自定義Processor(繼承WxMsgProcessor<TRecMsg>或者子類)時,RecInsCreater屬性如果不賦值,
  則系統底層在 創建對應的實例時,通過泛型的 new() 機制實現,屬於反射。

六. 終極定製
 前面基本都能滿足所有的定製需求了,但是如果可能...你還想要更大的定製自由度,那麼我這裏也盡力的滿足你。在生命週期擴展中其實還有一個方法,這個方法是總的執行方法,其他的生命週期事件也都是在這裏觸發:
  ResultMo<WxMsgContext> Execute(string recMsgXml)

 如果你希望自己定義一套完整的生命週期,OK,重寫這裏即可。系統將幫你完成驗籤,消息對象賦值,加密等邊緣操作,只需要記住一件事情,如果你重寫了這裏,上述的幾種模式和其他生命週期事件將無效。

 

=============================

 

如果你還有其他問題,歡迎關注公衆號(OSSCoder)

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章