C#微信公眾號(hào)開發(fā)之接收事件推送與消息排重的方法_第1頁
C#微信公眾號(hào)開發(fā)之接收事件推送與消息排重的方法_第2頁
C#微信公眾號(hào)開發(fā)之接收事件推送與消息排重的方法_第3頁
C#微信公眾號(hào)開發(fā)之接收事件推送與消息排重的方法_第4頁
C#微信公眾號(hào)開發(fā)之接收事件推送與消息排重的方法_第5頁
已閱讀5頁,還剩7頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、C#微信公眾號(hào)開發(fā)之接收事件推送與消息排重的方法這篇文章主要介紹了C#微信公眾號(hào)開發(fā)之接收事件推送與消息排重的方法,詳細(xì)分析了事件推送與消息排重的使用技巧,對(duì)微信開發(fā)有一定參考借鑒價(jià)值,需要的朋友可以參考下本文實(shí)例講述了C#微信公眾號(hào)開發(fā)之接收事件推送與消息排重的方法。分享給大家供大家參考。具體分析如下: 微信服務(wù)器在5秒內(nèi)收不到響應(yīng)會(huì)斷掉連接,并且重新發(fā)起請(qǐng)求,總共重試三次。這樣的話,問題就來了。有這樣一個(gè)場(chǎng)景:當(dāng)用戶關(guān)注微信賬號(hào)時(shí),獲取當(dāng)前用戶信息,然后將信息寫到數(shù)據(jù)庫中。類似于pc端網(wǎng)站的注冊(cè)。可能由于這個(gè)關(guān)注事件中,我們需要處理的業(yè)務(wù)邏輯比較復(fù)雜。如送積分啊,寫用戶日志啊,分配用戶組啊

2、。等等一系列的邏輯需要執(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。我

3、的思路是: 新建類BaseMsg,有三個(gè)屬性分別是FromUser,MsgFlag,CreateTime。代碼如下: 復(fù)制代碼 代碼如下:public class BaseMsg / <summary> / 發(fā)送者標(biāo)識(shí) / </summary> public string FromUser get; set; / <summary> / 消息表示。普通消息時(shí),為msgid,事件消息時(shí),為事件的創(chuàng)建時(shí)間 / </summary> public string MsgFlag get; set; / <summary> / 添加到隊(duì)列的時(shí)間

4、 / </summary> public DateTime CreateTime get; set; 創(chuàng)建個(gè)靜態(tài)列表_queue,用來存儲(chǔ)消息列表,列表的類型是List<BaseMsg>. 在處理微信消息體前,首先判斷列表是否實(shí)例化,如果沒有實(shí)例化則實(shí)例化,否則判斷列表的長(zhǎng)度是否大于或等于50(這個(gè)可以自定義,用處就是微信并發(fā)的消息量),如果大于或等于50,則保留20秒內(nèi)未響應(yīng)的消息(5秒重試一次,總共重試3次,就是15秒,保險(xiǎn)起見這里寫20秒)。 獲取當(dāng)前消息體的消息類型,并根據(jù)_queue判斷當(dāng)前消息是否已經(jīng)請(qǐng)求了。如果是事件則保存FromUser和創(chuàng)建時(shí)間。如果是

5、普通消息則保存MsgFlag。下面是代碼: 復(fù)制代碼 代碼如下:if (_queue = null) _queue = new List<BaseMsg>(); else if(_queue.Count>=50) _queue = _queue.Where(q => return q.CreateTime.AddSeconds(20) > DateTime.Now; ).ToList();/保留20秒內(nèi)未響應(yīng)的消息 XElement xdoc = XElement.Parse(xml); var msgtype = xdoc.Element("MsgTy

6、pe").Value.ToUpper(); var FromUserName = xdoc.Element("FromUserName").Value; var MsgId = xdoc.Element("MsgId").Value; var CreateTime = xdoc.Element("CreateTime").Value; MsgType type = (MsgType)Enum.Parse(typeof(MsgType), msgtype); if (type!=MsgType.EVENT) if (_queu

7、e.FirstOrDefault(m => return m.MsgFlag = MsgId; ) = null) _queue.Add(new BaseMsg CreateTime = DateTime.Now, FromUser = FromUserName, MsgFlag = MsgId ); else return null; else if (_queue.FirstOrDefault(m => return m.MsgFlag = CreateTime; ) = null) _queue.Add(new BaseMsg CreateTime = DateTime.No

8、w, FromUser = FromUserName, MsgFlag = CreateTime ); else return null; 當(dāng)消息已經(jīng)存在隊(duì)列中時(shí),則不轉(zhuǎn)換當(dāng)前的消息為實(shí)體了,直接返回null,調(diào)用的時(shí)候,當(dāng)返回null時(shí)就不做任何處理。 下面開始講解事件消息。接上篇講。所有的消息都繼承BaseMessage,而所有的事件類型都包含一個(gè)Event的屬性。這里為了方便調(diào)用,將消息 復(fù)制代碼 代碼如下:/ <summary> / 事件類型枚舉 / </summary> public enum Event / <summary> / 非事件類型 /

9、 </summary> NOEVENT, / <summary> / 訂閱 / </summary> SUBSCRIBE, / <summary> / 取消訂閱 / </summary> UNSUBSCRIBE, / <summary> / 掃描帶參數(shù)的二維碼 / </summary> SCAN, / <summary> / 地理位置 / </summary> LOCATION, / <summary> / 單擊按鈕 / </summary> CLICK, / &

10、lt;summary> / 鏈接按鈕 / </summary> VIEW, / <summary> / 掃碼推事件 / </summary> SCANCODE_PUSH, / <summary> / 掃碼推事件且彈出“消息接收中”提示框 / </summary> SCANCODE_WAITMSG, / <summary> / 彈出系統(tǒng)拍照發(fā)圖 / </summary> PIC_SYSPHOTO, / <summary> / 彈出拍照或者相冊(cè)發(fā)圖 / </summary> PIC_P

11、HOTO_OR_ALBUM, / <summary> / 彈出微信相冊(cè)發(fā)圖器 / </summary> PIC_WEIXIN, / <summary> / 彈出地理位置選擇器 / </summary> LOCATION_SELECT, / <summary> / 模板消息推送 / </summary> TEMPLATESENDJOBFINISH 定義好枚舉后,就是定義消息實(shí)體了。 關(guān)注/取消關(guān)注事件 xml數(shù)據(jù)包如下: 復(fù)制代碼 代碼如下:<xml> <ToUserName><!CDATAto

12、User></ToUserName> <FromUserName><!CDATAFromUser></FromUserName> <CreateTime>123456789</CreateTime> <MsgType><!CDATAevent></MsgType> <Event><!CDATAsubscribe></Event> </xml> 對(duì)應(yīng)的實(shí)體: 復(fù)制代碼 代碼如下:/ <summary> / 訂閱/取消訂閱事件

13、 / </summary> public class SubEventMessage : EventMessage private string _eventkey; / <summary> / 事件KEY值,qrscene_為前綴,后面為二維碼的參數(shù)值(已去掉前綴,可以直接使用) / </summary> public string EventKey get return _eventkey; set _eventkey = value.Replace("qrscene_", ""); / <summary&g

14、t; / 二維碼的ticket,可用來換取二維碼圖片 / </summary> public string Ticket get; set; 這里需要注意的是,當(dāng)用戶掃描帶參數(shù)的二維碼時(shí),如果用戶沒有關(guān)注當(dāng)前公眾號(hào),用戶關(guān)注時(shí),會(huì)在消息體中帶上qrscene_參數(shù),和Ticket,所以這里定義了兩個(gè)屬性:EventKey,Ticket。當(dāng)給EventKey賦值時(shí),替換掉qrscene_,因?yàn)槲覀冋嬲枰木褪呛竺娴膮?shù)。 掃描帶參數(shù)二維碼事件 用戶掃描帶場(chǎng)景值二維碼時(shí),可能推送一下兩種事件: 如果用戶還未關(guān)注公眾號(hào),則用戶可以關(guān)注公眾號(hào),關(guān)注后微信會(huì)將帶場(chǎng)景值關(guān)注事件推送給開發(fā)者。

15、 如果用戶已經(jīng)關(guān)注公眾號(hào),則微信會(huì)將帶場(chǎng)景值掃描事件推送給開發(fā)者。、 第一種上面已經(jīng)講了,這里就只說明下第二種。 用戶已關(guān)注時(shí)的事件推送 xml包如下: 復(fù)制代碼 代碼如下:<xml> <ToUserName><!CDATAtoUser></ToUserName> <FromUserName><!CDATAFromUser></FromUserName> <CreateTime>123456789</CreateTime> <MsgType><!CDATAevent&g

16、t;</MsgType> <Event><!CDATASCAN></Event> <EventKey><!CDATASCENE_VALUE></EventKey> <Ticket><!CDATATICKET></Ticket> </xml> 對(duì)應(yīng)的實(shí)體如下: 復(fù)制代碼 代碼如下:/ <summary> / 掃描帶參數(shù)的二維碼實(shí)體 / </summary> public class ScanEventMessage : EventMessag

17、e / <summary> / 事件KEY值,是一個(gè)32位無符號(hào)整數(shù),即創(chuàng)建二維碼時(shí)的二維碼scene_id / </summary> public string EventKey get; set; / <summary> / 二維碼的ticket,可用來換取二維碼圖片 / </summary> public string Ticket get; set; 上報(bào)地理位置事件 當(dāng)公眾號(hào)開啟上報(bào)地理位置功能后,每次進(jìn)入公眾號(hào)會(huì)話時(shí),用戶同意上報(bào)地理位置后,都會(huì)在進(jìn)入時(shí)上報(bào)地理位置,或在進(jìn)入回話后每5秒上報(bào)一次地理位置,公眾號(hào)可以再公眾平臺(tái)的后臺(tái)中修

18、改設(shè)置。上報(bào)地理位置時(shí),微信會(huì)將上報(bào)地理位置事件推送到開發(fā)者填寫的url。 xml數(shù)據(jù)包如下: 復(fù)制代碼 代碼如下:<xml> <ToUserName><!CDATAtoUser></ToUserName> <FromUserName><!CDATAfromUser></FromUserName> <CreateTime>123456789</CreateTime> <MsgType><!CDATAevent></MsgType> <Event&

19、gt;<!CDATALOCATION></Event> <Latitude>23.137466</Latitude> <Longitude>113.352425</Longitude> <Precision>119.385040</Precision> </xml> 對(duì)應(yīng)的實(shí)體如下: 復(fù)制代碼 代碼如下:/ <summary> / 上報(bào)地理位置實(shí)體 / </summary> public class LocationEventMessage : EventMess

20、age / <summary> / 地理位置緯度 / </summary> public string Latitude get; set; / <summary> / 地理位置經(jīng)度 / </summary> public string Longitude get; set; / <summary> / 地理位置精度 / </summary> public string Precision get; set; 自定義菜單事件常用的事件有:click,view,scancode_puth,scancode_waitmsg,l

21、ocation_select。另外還有三種發(fā)圖的事件,由于并不常用,筆者也沒想到使用場(chǎng)景,再次就不一一講述了,有興趣的可以自己研究下,或者和我進(jìn)行交流。 click事件推送的xml數(shù)據(jù)包: 復(fù)制代碼 代碼如下:<xml> <ToUserName><!CDATAtoUser></ToUserName> <FromUserName><!CDATAFromUser></FromUserName> <CreateTime>123456789</CreateTime> <MsgType>

22、;<!CDATAevent></MsgType> <Event><!CDATACLICK></Event> <EventKey><!CDATAEVENTKEY></EventKey> </xml> view事件推送的xml數(shù)據(jù)包和click的格式是一樣的,所以定義一個(gè)類就可以了,如下: 復(fù)制代碼 代碼如下:/ <summary> / 普通菜單事件,包括click和view / </summary> public class NormalMenuEventMessa

23、ge : EventMessage / <summary> / 事件KEY值,設(shè)置的跳轉(zhuǎn)URL / </summary> public string EventKey get; set; scancode事件的xml數(shù)據(jù)包如下: 復(fù)制代碼 代碼如下:<xml><ToUserName><!CDATAToUserName></ToUserName> <FromUserName><!CDATAFromUserName></FromUserName> <CreateTime>1419

24、265698</CreateTime> <MsgType><!CDATAevent></MsgType> <Event><!CDATAscancode_push></Event> <EventKey><!CDATAEventKey></EventKey> <ScanCodeInfo><ScanType><!CDATAqrcode></ScanType> <ScanResult><!CDATA </Scan

25、CodeInfo> </xml> 對(duì)應(yīng)的實(shí)體如下: 復(fù)制代碼 代碼如下:/ <summary> / 菜單掃描事件 / </summary> public class ScanMenuEventMessage : EventMessage / <summary> / 事件KEY值 / </summary> public string EventKey get; set; / <summary> / 掃碼類型。qrcode是二維碼,其他的是條碼 / </summary> public string ScanT

26、ype get; set; / <summary> / 掃描結(jié)果 / </summary> public string ScanResult get; set; 至此,當(dāng)前常用的事件類型消息都已定義完畢,結(jié)合上一篇所講的,將xml數(shù)據(jù)包轉(zhuǎn)換成對(duì)象的完整代碼如下: 復(fù)制代碼 代碼如下:public class MessageFactory private static List<BaseMsg> _queue; public static BaseMessage CreateMessage(string xml) if (_queue = null) _que

27、ue = new List<BaseMsg>(); else if(_queue.Count>=50) _queue = _queue.Where(q => return q.CreateTime.AddSeconds(20) > DateTime.Now; ).ToList();/保留20秒內(nèi)未響應(yīng)的消息 XElement xdoc = XElement.Parse(xml); var msgtype = xdoc.Element("MsgType").Value.ToUpper(); var FromUserName = xdoc.Elem

28、ent("FromUserName").Value; var MsgId = xdoc.Element("MsgId").Value; var CreateTime = xdoc.Element("CreateTime").Value; MsgType type = (MsgType)Enum.Parse(typeof(MsgType), msgtype); if (type!=MsgType.EVENT) if (_queue.FirstOrDefault(m => return m.MsgFlag = MsgId; ) =

29、null) _queue.Add(new BaseMsg CreateTime = DateTime.Now, FromUser = FromUserName, MsgFlag = MsgId ); else return null; else if (_queue.FirstOrDefault(m => return m.MsgFlag = CreateTime; ) = null) _queue.Add(new BaseMsg CreateTime = DateTime.Now, FromUser = FromUserName, MsgFlag = CreateTime ); els

30、e return null; switch (type) case MsgType.TEXT: return Utils.ConvertObj<TextMessage>(xml); case MsgType.IMAGE: return Utils.ConvertObj<ImgMessage>(xml); case MsgType.VIDEO: return Utils.ConvertObj<VideoMessage>(xml); case MsgType.VOICE: return Utils.ConvertObj<VoiceMessage>(xml); case MsgType.LINK: return Utils.ConvertO

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論