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