微信公眾號開發(fā)C#系列-7、消息管理-接收事件推送

1、概述
在微信用戶和公眾號產(chǎn)生交互的過程中,用戶的某些操作會(huì)使得微信服務(wù)器通過事件推送的形式通知到開發(fā)者在開發(fā)者中心處設(shè)置的服務(wù)器地址,從而開發(fā)者可以獲取到該信息。其中,某些事件推送在發(fā)生后,是允許開發(fā)者回復(fù)用戶的,某些則不允許
我們在上一篇微信公眾號開發(fā)C#系列-6、消息管理-普通消息接受處理中講到,微信的消息可以大體分為兩種類型,一種是包括:文本,語音,圖片等的普通消息,另一種就是本篇要將的事件類型。包括:關(guān)注/取消關(guān)注事件,掃描帶參數(shù)二維碼事件,上報(bào)地理位置事件,自定義菜單相關(guān)事件等,本篇一一進(jìn)行講解。介于偏于內(nèi)容過多易產(chǎn)生閱讀疲勞,對于自定義菜單相關(guān)事件的處理我們放在下一篇中講解。
這里的消息指的是傳統(tǒng)的微信公眾平臺(tái)消息交互,微信用戶向公眾號發(fā)送消息后,公眾號回復(fù)消息給微信用戶。包括以下類型:
- 關(guān)注/取消關(guān)注事件:subscribe/unsubscribe
- 掃描帶參數(shù)二維碼事件:scan
- 上報(bào)地理位置事件:location
- 自定義菜單事件
- 點(diǎn)擊菜單拉取消息時(shí)的事件推送
- 點(diǎn)擊菜單跳轉(zhuǎn)鏈接時(shí)的事件推送
本篇主要介紹前三種。
2、實(shí)現(xiàn)方式
使用Senparc.Weixin框架來快速處理各種接收事件推送,實(shí)現(xiàn)非常簡單,自定義一個(gè)繼承MessageHandler的類,重寫這些類型的方法即可。注意:DefaultResponseMessage必須重寫,用于返回沒有處理過的消息類型(也可以用于默認(rèn)消息,如幫助信息等);其中所有原OnXX的抽象方法已經(jīng)都改為虛方法,可以不必每個(gè)都重寫。若不重寫,默認(rèn)返回DefaultResponseMessage方法中的結(jié)果。
自定義消息處理類:
public partial class CustomMessageHandler : MessageHandler<MessageContext<IRequestMessageBase, IResponseMessageBase>>
{
public CustomMessageHandler(Stream inputStream, int maxRecordCount = 0)
: base(inputStream, null, maxRecordCount)
{
WeixinContext.ExpireMinutes = 3;
}
public override void OnExecuting()
{
//測試MessageContext.StorageData
if (CurrentMessageContext.StorageData == null)
{
CurrentMessageContext.StorageData = 0;
}
base.OnExecuting();
}
public override void OnExecuted()
{
base.OnExecuted();
CurrentMessageContext.StorageData = ((int)CurrentMessageContext.StorageData) + 1;
}
}
定義好事件處理類后,分別重寫上面提到幾種接收事件推送的事件即可。
我們可以通過重寫MessageHandler里的這幾種類型方法來處理我們的業(yè)務(wù),當(dāng)然也可以只重寫需要的部分類型,不需要的類型可以不重寫,只需要定義一個(gè)統(tǒng)一的DefaultResponseMessage
public override IResponseMessageBase DefaultResponseMessage(IRequestMessageBase requestMessage)
{
//所有沒有被處理的消息會(huì)默認(rèn)返回這里的結(jié)果
var responseMessage = this.CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = "這條消息來自DefaultResponseMessage。";
return responseMessage;
}
3、消息的去重的重要性
上一篇我們就已經(jīng)提到過微信服務(wù)器在5秒內(nèi)收不到響應(yīng)會(huì)斷掉連接,并且重新發(fā)起請求,總共重試三次。如此以來,我們模擬有這樣一個(gè)場景:當(dāng)用戶關(guān)注微信賬號時(shí),獲取當(dāng)前用戶信息,然后將信息寫到數(shù)據(jù)庫中,類似網(wǎng)站的注冊。假設(shè)這個(gè)關(guān)注事件中,我們需要處理比較復(fù)雜的業(yè)務(wù)邏輯。如送積分,寫用戶日志,分配用戶組等等一系列的邏輯需要執(zhí)行,或者網(wǎng)絡(luò)環(huán)境比較復(fù)雜,無法保證5秒內(nèi)響應(yīng)當(dāng)前用戶的操作,那如果當(dāng)操作尚未完成,微信服務(wù)器又給我們的服務(wù)器推送了一條相同的關(guān)注事件,我們將再次執(zhí)行我們的那些邏輯,這樣就有可能導(dǎo)致數(shù)據(jù)庫中出現(xiàn)重復(fù)的數(shù)據(jù)(有的童鞋就會(huì)說了,我在插入數(shù)據(jù)之前先判斷當(dāng)前是否已經(jīng)存在了,如果存在了就不執(zhí)行插入的操作。我想說的是,我當(dāng)初也是這樣想的,但真實(shí)的運(yùn)行環(huán)境和我們的調(diào)試環(huán)境還是有差距的,直到發(fā)現(xiàn)數(shù)據(jù)庫中有不少重復(fù)的用戶信息時(shí),我才發(fā)現(xiàn)消息去重的重要性。)。
消息的去重普通消息和事件消息是有區(qū)別的。普通消息使用msgid,而事件消息使用FromUserName + CreateTime。
4、關(guān)注/取消關(guān)注事件
用戶在關(guān)注與取消關(guān)注公眾號時(shí),微信會(huì)把這個(gè)事件推送到開發(fā)者填寫的URL。方便開發(fā)者給用戶下發(fā)歡迎消息或者做帳號的解綁。
假如服務(wù)器無法保證在五秒內(nèi)處理并回復(fù),可以直接回復(fù)空串,微信服務(wù)器不會(huì)對此作任何處理,并且不會(huì)發(fā)起重試。
關(guān)注或取消事件推送XML數(shù)據(jù)包示例:
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[FromUser]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[subscribe]]></Event>
</xml>
參數(shù)說明:
參數(shù) 描述
ToUserName 開發(fā)者微信號
FromUserName 發(fā)送方帳號(一個(gè)OpenID)
CreateTime 消息創(chuàng)建時(shí)間 (整型)
MsgType 消息類型,event
Event 事件類型,subscribe(訂閱)、unsubscribe(取消訂閱)
4.1 關(guān)注事件
關(guān)注事件我們只需要重寫OnEvent_SubscribeRequest事件代碼即可,如下我們返回了一個(gè)文本消息,實(shí)現(xiàn)代碼參考:
/// <summary>
/// 訂閱(關(guān)注)事件
/// </summary>
/// <returns></returns>
public override IResponseMessageBase OnEvent_SubscribeRequest(RequestMessageEvent_Subscribe requestMessage)
{
var responseMessage = CreateResponseMessage<ResponseMessageNews>();
foreach (var model in messageList)
{
responseMessage.Articles.Add(new Article()
{
Title = "國思公眾號",
Description = "歡迎關(guān)注國思軟件公眾號,更多內(nèi)容穩(wěn)步官網(wǎng),多謝!",
PicUrl = "http://www.rdiframework.net/WeiXin.png",
Url = "http://www.rdiframework.net/"
});
}
return responseMessage;
}

在上面的關(guān)注事件中,用戶關(guān)注公眾號就會(huì)自動(dòng)執(zhí)行上面的事件代碼,我們就可以在事件代碼中做相關(guān)的業(yè)務(wù)處理,如綁定用戶分組、增加用戶到本地等等。同時(shí)推送一條歡迎消息返回到用戶手機(jī)上。
4.2 取消關(guān)注事件
取消關(guān)注事件與關(guān)注事件類似,主要是事件變成了unsubscribe(取消關(guān)注)。取消關(guān)注事件-unsubscribe的主要意義在于及時(shí)刪除網(wǎng)站應(yīng)用中已經(jīng)記錄的OpenID綁定,消除冗余數(shù)據(jù),并且關(guān)注用戶流失的情況。
取消關(guān)注事件我們只需要重寫OnEvent_UnsubscribeRequest事件代碼即可,如下我們返回了一個(gè)文本消息,實(shí)現(xiàn)代碼參考:
/// <summary>
/// 退訂/取消關(guān)注
/// 實(shí)際上用戶無法收到非訂閱賬號的消息,所以這里可以隨便寫。
/// unsubscribe事件的意義在于及時(shí)刪除網(wǎng)站應(yīng)用中已經(jīng)記錄的OpenID綁定,消除冗余數(shù)據(jù)。并且關(guān)注用戶流失的情況。
/// </summary>
/// <returns></returns>
public override IResponseMessageBase OnEvent_UnsubscribeRequest(RequestMessageEvent_Unsubscribe requestMessage)
{
int returnValue = RDIFrameworkService.Instance.WeixinBasicService.UserUnsubscribeByOpenId(Id,requestMessage.FromUserName);//退
var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = "有空再來";
return responseMessage;
}
上面的代碼在用戶取消公眾號的關(guān)注時(shí)就會(huì)自動(dòng)執(zhí)行,可以看到我們有一行代碼針對用戶取消關(guān)注時(shí)執(zhí)行的業(yè)務(wù)邏輯,同時(shí)返回了一個(gè)文本消息。實(shí)際用戶已經(jīng)取消關(guān)注,返回的消息也返回不到用戶手機(jī)上的。
5、掃描帶參數(shù)二維碼事件
用戶掃描帶場景值二維碼時(shí),可能推送以下兩種事件:
- 如果用戶還未關(guān)注公眾號,則用戶可以關(guān)注公眾號,關(guān)注后微信會(huì)將帶場景值關(guān)注事件推送給開發(fā)者。
- 如果用戶已經(jīng)關(guān)注公眾號,則微信會(huì)將帶場景值掃描事件推送給開發(fā)者。
5.1 接口展示與實(shí)現(xiàn)方式
對于第一種上面已經(jīng)講了,這里就只說明下第二種。
推送XML數(shù)據(jù)包示例:
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[FromUser]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[SCAN]]></Event>
<EventKey><![CDATA[SCENE_VALUE]]></EventKey>
<Ticket><![CDATA[TICKET]]></Ticket>
</xml>
參數(shù)說明:
參數(shù) 描述
ToUserName 開發(fā)者微信號
FromUserName 發(fā)送方帳號(一個(gè)OpenID)
CreateTime 消息創(chuàng)建時(shí)間 (整型)
MsgType 消息類型,event
Event 事件類型,SCAN
EventKey 事件KEY值,是一個(gè)32位無符號整數(shù),即創(chuàng)建二維碼時(shí)的二維碼scene_id
Ticket 二維碼的ticket,可用來換取二維碼圖片
對于生成帶參數(shù)的二維碼我們會(huì)在后面的文章中專門介紹,這兒我們了解一個(gè)這個(gè)概念。為了滿足用戶渠道推廣分析和用戶帳號綁定等場景的需要,公眾平臺(tái)提供了生成帶參數(shù)二維碼的接口。使用該接口可以獲得多個(gè)帶不同場景值的二維碼,用戶掃描后,公眾號可以接收到事件推送。具體官方技術(shù)文檔可參考:生成帶參數(shù)的二維碼
目前有2種類型的二維碼:
1、臨時(shí)二維碼,是有過期時(shí)間的,最長可以設(shè)置為在二維碼生成后的30天(即2592000秒)后過期,但能夠生成較多數(shù)量。臨時(shí)二維碼主要用于帳號綁定等不要求二維碼永久保存的業(yè)務(wù)場景
2、永久二維碼,是無過期時(shí)間的,但數(shù)量較少(目前為最多10萬個(gè))。永久二維碼主要用于適用于帳號綁定、用戶來源統(tǒng)計(jì)等場景。
掃描帶參數(shù)二維碼事件只需要重寫OnEvent_ScanRequest事件代碼即可,如下我們返回了一個(gè)文本消息,實(shí)現(xiàn)代碼參考:
public override IResponseMessageBase OnEvent_ScanRequest(RequestMessageEvent_Scan requestMessage)
{
//通過掃描關(guān)注
var responseMessage = CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = responseMessage.Content ?? string.Format("歡迎關(guān)注國思軟件,通過掃描二維碼進(jìn)入,場景值:{0}", requestMessage.EventKey);
return responseMessage;
}
在上面的代碼中用戶掃描了帶場景值的二維碼進(jìn)入公眾號后我們返回了一個(gè)提示的文本消息。這是非常有用的功能,常用途推廣,可以根據(jù)不同的二維碼場景值分別做不同的業(yè)務(wù)處理,如可以統(tǒng)計(jì)關(guān)注的每一個(gè)粉絲從哪里來的,做到渠道推廣分析,但是關(guān)注的都是同一個(gè)公眾號。
5.2 生成帶參數(shù)的二維碼用途
微信公眾號生成帶參數(shù)的二維碼有何用途?
- 可以區(qū)分粉絲來源,只需要生成不同的帶參數(shù)的二維碼,把這些二維碼分別投放到各個(gè)渠道,粉絲通過這些渠道二維碼進(jìn)來就可以區(qū)分粉絲來源,微號幫后臺(tái)渠道粉絲列表中有粉絲數(shù)及明細(xì);
- 粉絲通過掃描渠道二維碼關(guān)注公眾號,會(huì)打標(biāo)簽分組,比如粉絲掃商店A、B的二維碼進(jìn)來的, 在微信公眾號后來的用戶管理中可查看到商店A/B二維碼名下的粉絲明細(xì)及分組情況;
- 可以生成多個(gè)不同的渠道二維碼配置不同的營銷活動(dòng),設(shè)置不同的關(guān)注回復(fù)信息,讓粉絲第一時(shí)間了解活動(dòng)動(dòng)機(jī),是否有興趣參與等等;
- 可以利用渠道二維碼生成功能,可以實(shí)現(xiàn)微信收款前關(guān)注公眾號,間接分析粉絲后續(xù)消費(fèi)情況;
- 考核推廣員完成任務(wù)的進(jìn)度,如以推廣名字生成多不個(gè)同的二維碼,分配給不同的推廣員,每個(gè)推廣員吸引了多少粉絲關(guān)注公眾號,微號幫后臺(tái)都可以一一明細(xì);
- 帶參數(shù)的二維碼也叫渠道二維碼或者場景二維碼,生存的數(shù)量有限,且是永久二維碼。當(dāng)數(shù)量用完后可以刪除一些不用的二維碼釋放出來,二次利用。

6、上報(bào)地理位置事件
用戶同意上報(bào)地理位置后,每次進(jìn)入公眾號會(huì)話時(shí),都會(huì)在進(jìn)入時(shí)上報(bào)地理位置,或在進(jìn)入會(huì)話后每5秒上報(bào)一次地理位置,公眾號可以在公眾平臺(tái)網(wǎng)站中修改以上設(shè)置。上報(bào)地理位置時(shí),微信會(huì)將上報(bào)地理位置事件推送到開發(fā)者填寫的URL。要獲取用戶地址位置,需要在微信公眾平臺(tái)開發(fā)者中心開啟上報(bào)地理位置功能,開啟之后會(huì)在用戶首次進(jìn)入公眾號時(shí),彈出是否允許上報(bào)地理位置選項(xiàng),如果選擇允許則在用戶每次進(jìn)入公眾號會(huì)話的時(shí)候微信會(huì)以XML形式將用戶的地理位置上報(bào)到你開發(fā)者中心填寫的URL上。
注意:用戶地理位置是被動(dòng)獲取的,需用戶同意后才會(huì)上報(bào),微信公眾平臺(tái)開發(fā)不能主動(dòng)獲取用戶地理位置。
推送XML數(shù)據(jù)包示例:
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[LOCATION]]></Event>
<Latitude>23.137466</Latitude>
<Longitude>113.352425</Longitude>
<Precision>119.385040</Precision>
</xml>
參數(shù)說明:
參數(shù) 描述
ToUserName 開發(fā)者微信號
FromUserName 發(fā)送方帳號(一個(gè)OpenID)
CreateTime 消息創(chuàng)建時(shí)間 (整型)
MsgType 消息類型,event
Event 事件類型,LOCATION
Latitude 地理位置緯度
Longitude 地理位置經(jīng)度
Precision 地理位置精度
上報(bào)地理位置事件只需要重寫OnEvent_LocationRequest事件代碼即可,如下我們返回了一個(gè)文本消息,實(shí)現(xiàn)代碼參考:
public override IResponseMessageBase OnEvent_LocationRequest(RequestMessageEvent_Location requestMessage)
{
//這里是微信客戶端(通過微信服務(wù)器)自動(dòng)發(fā)送過來的位置信息
var responseMessage = CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = "這里寫什么都無所謂,比如:上帝愛你!";
return responseMessage;//這里也可以返回null(需要注意寫日志時(shí)候null的問題)
}
上報(bào)地理位置用處非常多,可以用維度和經(jīng)度獲取城市代號,調(diào)用天氣Api,也可以用來監(jiān)測企業(yè)員工的位置進(jìn)行微信考勤。在微信運(yùn)營的時(shí)候,用戶地理位置還是我們進(jìn)行營銷策劃、廣告活動(dòng)投放、用戶精準(zhǔn)營銷的重要依據(jù)。
參考文章
Senparc.Weixin SDK + 官網(wǎng)示例源代碼
RDIFramework.NET — 基于.NET的快速信息化系統(tǒng)開發(fā)框架 — 系列目錄
RDIFramework.NET ━ .NET快速信息化系統(tǒng)開發(fā)框架 ━ 工作流程組件介紹
RDIFramework.NET框架SOA解決方案(集Windows服務(wù)、WinForm形式與IIS形式發(fā)布)-分布式應(yīng)用
RDIFramework.NET代碼生成器全新V3.5版本發(fā)布-重大升級
一路走來數(shù)個(gè)年頭,感謝RDIFramework.NET框架的支持者與使用者,大家可以通過下面的地址了解詳情。
RDIFramework.NET官方網(wǎng)站:http://www.rdiframework.net/
RDIFramework.NET官方博客:http://blog.rdiframework.net/
同時(shí)需要說明的,以后的所有技術(shù)文章以官方網(wǎng)站為準(zhǔn),歡迎大家收藏!
RDIFramework.NET框架由專業(yè)團(tuán)隊(duì)長期打造、一直在更新、一直在升級,請放心使用!
歡迎關(guān)注RDIFramework.net框架官方公眾微信(微信號:guosisoft),及時(shí)了解最新動(dòng)態(tài)。
掃描二維碼立即關(guān)注

作者:
RDIF
出處:
http://www.rzrgm.cn/huyong/
Email:
406590790@qq.com
QQ:
406590790
微信:
13005007127(同手機(jī)號)
框架官網(wǎng):
http://www.guosisoft.com/
http://www.rdiframework.net/
框架其他博客:
http://blog.csdn.net/chinahuyong
http://www.rzrgm.cn/huyong
國思RDIF開發(fā)框架
,
給用戶和開發(fā)者最佳的.Net框架平臺(tái)方案,為企業(yè)快速構(gòu)建跨平臺(tái)、企業(yè)級的應(yīng)用提供強(qiáng)大支持。
關(guān)于作者:系統(tǒng)架構(gòu)師、信息系統(tǒng)項(xiàng)目管理師、DBA。專注于微軟平臺(tái)項(xiàng)目架構(gòu)、管理和企業(yè)解決方案,多年項(xiàng)目開發(fā)與管理經(jīng)驗(yàn),曾多次組織并開發(fā)多個(gè)大型項(xiàng)目,在面向?qū)ο蟆⒚嫦蚍?wù)以及數(shù)據(jù)庫領(lǐng)域有一定的造詣?,F(xiàn)主要從事基于
RDIF
框架的技術(shù)開發(fā)、咨詢工作,主要服務(wù)于金融、醫(yī)療衛(wèi)生、鐵路、電信、物流、物聯(lián)網(wǎng)、制造、零售等行業(yè)。
如有問題或建議,請多多賜教!
本文版權(quán)歸作者和CNBLOGS博客共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,如有問題,可以通過微信、郵箱、QQ等聯(lián)系我,非常感謝。

微信用戶和公眾號產(chǎn)生交互的過程中,用戶的某些操作會(huì)使得微信服務(wù)器通過事件推送的形式通知到開發(fā)者在開發(fā)者中心處設(shè)置的服務(wù)器地址,從而開發(fā)者可以獲取到該信息。其中,某些事件推送在發(fā)生后,是允許開發(fā)者回復(fù)用戶的,某些則不允許。本文主發(fā)講解關(guān)注/取消關(guān)注事件,掃描帶參數(shù)二維碼事件,上報(bào)地理位置事件的處理。同時(shí)講解這些事件在微信營銷中的應(yīng)用場景。
浙公網(wǎng)安備 33010602011771號