1. 程式人生 > >一個還算簡單的微信消息SDK(基於.Net Standard 2.0)

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

sch 入口 技術分享 ret 公眾 func exec 實體 blank

  雖然微信公眾號出現了好久,不過在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
{
   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)

技術分享

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