前言: 回顧上一節伺服器配置的內容,我們已經可以自己完成公眾號伺服器的配置。配置完成之後,我們就可以通過調用的方式,完成對消息管理的處理。當用戶關註公眾號或者發送消息的時候,我們應該啟用預設回覆,要不然用戶得不到回應, 從而導致丟失體驗。所以這一章節,我們將通過消息管理的方式,對用戶的信息進行處理, ...
前言:
回顧上一節伺服器配置的內容,我們已經可以自己完成公眾號伺服器的配置。配置完成之後,我們就可以通過調用的方式,完成對消息管理的處理。當用戶關註公眾號或者發送消息的時候,我們應該啟用預設回覆,要不然用戶得不到回應,
從而導致丟失體驗。所以這一章節,我們將通過消息管理的方式,對用戶的信息進行處理,完成公眾號消息回覆功能,實現公眾號與用戶之間的完整對話。
瞭解:
微信公眾平臺對信息做了比較清晰的分類,最基本的包括請求(Request)和響應(Response)兩大類信息,這兩類信息有分為文字、語音、圖片等格式。Senparc.Weixin.MP提供了MessageHandler消息處理類,這些類型在以枚舉的方式區分,
同時根據嚴格命名規則命名了所有類型的RequestMessage和ResponseMessage。在Senparc里也詳細說明瞭如何這個類的
開始:
第一步:
新建一個UserMessageHandler.cs,需要繼承Senparc.Weixin.MP.MessageHandlers<TC>這個抽象類,並重寫所有方法:
public class UserMessageHandler : MessageHandler<UserMessageContext> { /// <summary> /// 構造函數 /// </summary> /// <param name="inputStream">構造函數的inputStream用於接收來自微信伺服器的請求流(如果需要在外部處理,這裡也可以傳入XDocument)</param> /// <param name="postModel">微信公眾伺服器Post過來的加密參數集合(不包括PostData)</param> public UserMessageHandler(Stream inputStream, PostModel postModel) : base(inputStream, postModel) { } public override IResponseMessageBase DefaultResponseMessage(IRequestMessageBase requestMessage) { /* 所有沒有被處理的消息會預設返回這裡的結果 */ var responseMessage = this.CreateResponseMessage<ResponseMessageText>();//ResponseMessageText也可以是News等其他類型 responseMessage.Content = "這條消息來自DefaultResponseMessage。"; return responseMessage; } }
using Senparc.Weixin.Context; using Senparc.Weixin.MP.Entities; using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace WeiXinHandler { public class UserMessageContext: MessageContext<IRequestMessageBase, IResponseMessageBase> { public UserMessageContext() { /* * 註意:即使使用其他類實現IMessageContext, * 也務必在這裡進行下麵的初始化,尤其是設置當前時間, * 這個時間關係到及時從緩存中移除過期的消息,節約記憶體使用 */ base.MessageContextRemoved += UserMessageContext_MessageContextRemoved; } /// <summary> /// 當上下文過期,被移除時觸發的時間 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void UserMessageContext_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); //api.SendMessage(e.OpenId, "由於長時間未搭理客服,您的客服狀態已退出!"); } } }
重寫的方法對應了接收不同的Request類型,構造函數的inputStream用於接收來自微信伺服器的請求流
第二步:
基本用戶不同類型的請求,比如用戶向我們發送一條信息,那麼會最終會調用OnTextRequest這個方法,所以在不同的重寫方法內,實現自己的方法。
比如:我們對於文字(Text)信息進行這樣的處理,在UserMessageHandler中我們可以重寫方法OnTextRequest:
public override IResponseMessageBase OnTextRequest(RequestMessageText requestMessage) { var responseMessage = base.CreateResponseMessage<ResponseMessageText>(); responseMessage.Content = "您剛剛發送了文字信息:" + requestMessage.Content; //requestMessage.Content即用戶發過來的文字內容 return responseMessage; }
對於圖片信息進行這樣的處理,在UserMessageHandler中我們可以重寫方法OnImageRequest
/// <summary> /// 處理圖片請求 /// </summary> /// <param name="requestMessage"></param> /// <returns></returns> public override IResponseMessageBase OnImageRequest(RequestMessageImage requestMessage) { var responseMessage = CreateResponseMessage<ResponseMessageNews>(); responseMessage.Articles.Add(new Article() { Title = "您剛纔發送了圖片信息", Description = "您發送的圖片將會顯示在邊上", PicUrl = requestMessage.PicUrl, Url = "https://www.cnblogs.com/i3yuan/" }); return responseMessage; }
對於語音信息進行這樣的處理,在UserMessageHandler中我們可以重寫方法OnVoiceRequest
/// <summary> /// 處理語音請求 /// </summary> /// <param name="requestMessage"></param> /// <returns></returns> public override IResponseMessageBase OnVoiceRequest(RequestMessageVoice requestMessage) { //獲取公眾號 AccessTokenResult account = Senparc.Weixin.MP.CommonAPIs.CommonApi.GetToken(AppId, AppSecret); var responseMessage = CreateResponseMessage<ResponseMessageMusic>(); //上傳縮略圖 var uploadResult = Senparc.Weixin.MP.AdvancedAPIs.MediaApi.UploadTemporaryMedia(account.access_token, UploadMediaFileType.image, Server.GetMapPath("~/Images/Logo.jpg")); //設置音樂信息 responseMessage.Music.Title = "天籟之音"; responseMessage.Music.Description = "播放您上傳的語音"; responseMessage.Music.MusicUrl = "http://sdk.weixin.senparc.com/Media/GetVoice?mediaId=" + requestMessage.MediaId; responseMessage.Music.HQMusicUrl = "http://sdk.weixin.senparc.com/Media/GetVoice?mediaId=" + requestMessage.MediaId; responseMessage.Music.ThumbMediaId = uploadResult.media_id; return responseMessage; }
對於視頻信息進行這樣的處理,在UserMessageHandler中我們可以重寫方法OnVideoRequest
/// <summary> /// 處理視頻請求 /// </summary> /// <param name="requestMessage"></param> /// <returns></returns> public override IResponseMessageBase OnVideoRequest(RequestMessageVideo requestMessage) { var responseMessage = CreateResponseMessage<ResponseMessageText>(); responseMessage.Content = "您發送了一條視頻信息,ID:" + requestMessage.MediaId; return responseMessage; }
對於地理信息進行這樣的處理,在UserMessageHandler中我們可以重寫方法OnLocationRequest
/// <summary> /// 處理位置請求 /// </summary> /// <param name="requestMessage"></param> /// <returns></returns> public override IResponseMessageBase OnLocationRequest(RequestMessageLocation requestMessage) { var locationService = new LocationService(); var responseMessage = locationService.GetResponseMessage(requestMessage as RequestMessageLocation); return responseMessage; }
對於鏈接信息進行這樣的處理,在UserMessageHandler中我們可以重寫方法OnLinkRequest
/// <summary> /// 處理鏈接消息請求 /// </summary> /// <param name="requestMessage"></param> /// <returns></returns> public override IResponseMessageBase OnLinkRequest(RequestMessageLink requestMessage) { var responseMessage = ResponseMessageBase.CreateFromRequestMessage<ResponseMessageText>(requestMessage); responseMessage.Content = string.Format(@"您發送了一條連接信息: Title:{0} Description:{1} Url:{2}", requestMessage.Title, requestMessage.Description, requestMessage.Url); return responseMessage; }
第三步:
在Action中使用MessageHandler,返回對用戶的處理,在上一節中我們已經新建了WXController.cs,在其中通過Post的方式處理用戶的請求
[HttpPost] [ActionName("Index")] public Task<ActionResult> Post(PostModel postModel) { return Task.Factory.StartNew<ActionResult>(() => { if (!CheckSignature.Check(postModel.Signature, postModel.Timestamp, postModel.Nonce, Token)) { return new WeixinResult("參數錯誤!"); } var messageHandler = new UserMessageHandler(Request.InputStream); messageHandler.Execute(); //執行微信處理過程 return new FixWeixinBugWeixinResult(messageHandler); }).ContinueWith<ActionResult>(task => task.Result); } }
messageHandler.Execute();用於執行整個信息處理過程,其中會調用重寫的OnxxRequest方法
效果:
測試發送文本
通過測試公眾號,我們可以發現,當我們發送文本的時候,系統會對用戶的信息進行處理,完成公眾號消息回覆功能,實現公眾號與用戶之間的完整對話。
測試發送圖文消息
public override IResponseMessageBase OnTextRequest(RequestMessageText requestMessage) { var responseMessage = CreateResponseMessage<ResponseMessageNews>(); responseMessage.Articles.Add(new Article() { Title = "灌籃高手", Description = "灌籃高手", PicUrl = "http://images.cnblogs.com/cnblogs_com/i3yuan/1462639/o_timg%20(1).jpg", Url = "https://www.cnblogs.com/i3yuan/" }); return responseMessage; }
總結:
1.通過MessageHandler的簡單處理,我們就可以進行對用戶文本消息的處理,完成公眾號與用戶的會話
2.發送不同的消息,處理不同的回覆,實現更多類型的消息回覆
3.參考了如何使用MessageHandler簡化消息處理流程