程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 微信公眾平台SDK

微信公眾平台SDK

編輯:C#入門知識

微信公眾平台網址:https://mp.weixin.qq.com/

服務號說明:給企業和組織提供更強大的業務服務與用戶管理能力,幫助企業快速實現全新的公眾號服務平台。

.NETSDK: Loogn.WeiXinSDK.dll  (net4.0) 源碼暫時不提供

 

由於本人用的還是NOKIA-C5,沒用過微信,對微信的了解肯定沒你多,但公司有需求,只好硬著頭皮直接看接口文檔了。

看後發現也挺有意思的,一個很有用的作用就是,當用戶給公眾賬號發消息時,程序可以根據用戶發的內容自動回復用戶,比如給一個物流公司的公眾賬號發個運單號,

對方自動回復你這個運單號的物流詳細,感覺挺酷!為了說明方便,先給出申請好的公眾賬號信息:

下圖為表示上面查看物流詳細的消息流程(虛線的編號表示流程的順序):

 

微信會向你的URL發送兩大類消息:

一是用戶的一般消息,如上面用戶發的運單號;

二是用戶的行為(即文檔中說的事件)  ,如用戶關注了你的公眾賬號、掃描了公眾賬號的二維碼、點擊了你自定義的菜單等。

 你的URL就可以根據收到的消息類型和內容做出回應以實現強大的業務服務,如上面返回的物流詳細。消息全部是以XML格式傳遞,而SDK做的就是把XML轉換成.NET對象,以方便你編寫業務邏輯。消息的框架類圖表示為(點擊查看包括子類的全圖):

 首先有個消息基類,然後是收到的消息(RecEventBaseMsg)和回復的消息(ReplyBaseMsg),上面說了,收到的消息分兩大類,即一般消息(RecBaseMsg)和事件消息(EventBaseMsg),收到的消息類型用枚舉表示可以是:

其他的類型不說,而當MsgType為Event時,消息便是EventBaseMsg的子類了,所有EventBaseMsg的子類的MsgType都是Event,所以EventBaseMsg類型又有個EventType來區分不同的事件,如果你看過接口文檔,你應該知道,它的事件類型對我們判斷到底是哪個事件不太友好,掃描二維碼事件分了用戶已關注和未關注兩種情況,已關注時EvenType是scan,未關注時EventType是subscribe,而用戶關注事件的EventType也是subscribe,所以SDK裡又加了個MyEventType:

現在消息的流程基本清楚了,調用SDK回復消息如下:

 
     
       Token = ;
         =  signature = context.Request[ timestamp = context.Request[ nonce = context.Request[ (WeiXin.CheckSignature(signature, timestamp, nonce, Token))

                 replyMsg = xml =
, 
            WeiXin.RegisterMsgHandler<RecTextMsg>((msg) => =  +

            WeiXin.RegisterEventHandler<EventAttendMsg>((msg) => = 
  

 SDK包含了除(OAuth2.0網頁授權)的所有接口的封裝,類名及方法名都很明顯,這裡就不一一演示,有興趣的朋友可以下載dll自行測試,這是一張付費認證過的接口圖:

 

接下來談談實現的幾個細節:

一、憑據(access_token)過期

“access_token是公眾號的全局唯一票據,公眾號調用各接口時都需使用access_token。正常情況下access_token有效期為7200秒,重復獲取將導致上次獲取的access_token失效。公眾號可以使用AppID和AppSecret調用本接口來獲取access_token。AppID和AppSecret可在開發模式中獲得(需要已經成為開發者,且帳號沒有異常狀態)。”

根據文檔上說的,我們可以想到用緩存(不可能每次用每次取吧!),緩存代碼是很簡單的,主要是在這種情況下要能想到用緩存,下面是非完整代碼:

 
     
  access_token { ;  
         
          expires_in { ;  Dictionary<, Credential> creds =  Dictionary<, Credential>  TokenUrl =   Credential GetCredential( appId, =  (creds.TryGetValue(appId,  (cred.add_time.AddSeconds(cred.expires_in - ) <=  json = Util.HttpGet2(= Util.JsonTo<Credential>            creds[appId] = cred;
            

 

 二、錯誤碼信息

上面說到得到憑據的代碼不完整就是因為沒有處理可能返回的錯誤碼,微信錯誤碼以json格式返回,如:

{"errcode":40013,"errmsg":"invalid appid"}

大部分由我們主動調用的接口都有可能返回錯誤碼,錯誤碼格式與正常返回的數據格式完全不一樣,在SDK裡,我是這樣處理的,先定義好錯誤碼的模型類,我這裡叫ReturnCode,是因為錯誤碼裡還包含一個{"errcode":0,"errmsg":"ok"}的請求成功的情況:

       errcode { ;   errmsg { ;     + errcode +  + errmsg + 

定義有錯誤碼的返回消息類時我們就可以包含一個ReturnCode類型的屬性了,如創建二維碼接口:

       ticket { ;   expire_seconds { ;  ReturnCode error { ; 

從返回的json到QRCodeTicket對象的代碼大概就是這樣(其他的也是類似):

             json = (json.IndexOf() >  Util.JsonTo<QRCodeTicket>= = Util.JsonTo<ReturnCode>

所以用SDK調用接口後,得到的對象就可輕松判斷了:

             qrcode = WeiXin.CreateQRCode(,  (qrcode.error == 

            }

 

三、反序列化

微信接口返回的json有時候對我們映射到對象並不太直接(json格式太靈活了!),比如創建分組成功後返回的json:

: : 

如果想直接用json通過反序列化得到對象,那麼這個對象的類的定義有可能會是這樣:

      Group group { ;    id { ;   name { ; 

訪問的時候也會是gp.group.name,所以我說不太直接,我們想要的類的定義肯定是只有上面那個子類的樣子:

       id { ;   name { ; 

如果微信接口返回的是這樣:

: : 

就再好不過了,但人家的代碼,我們修改不了,我們只有自己想辦法.

1,要簡單類,2不手動分析json(如正則),3,不想多定義一個類,你有想到很好的方法嗎?如果有可以回復給我,而我選擇用字典來做中間轉換。

因為基本所有的json格式都可以反序列化為字典(嵌套字典,嵌套字典集合等),比如上面微信返回的json就可以用以下的類型來表示:

Dictionary<, Dictionary<, >>

json--->dict--->GroupInfo

 dict = Util.JsonTo<Dictionary<, Dictionary<, >>> gi =  gpdict = dict[= Convert.ToInt32(gpdict[= gpdict[].ToString();

 

四、消息處理的優化

"萬物簡單為美",我就是一個非常非常喜歡簡單的程序員。還記得最開始的那個消息(事件屬於消息,這裡統稱為消息)處理吧,我感覺是很簡單的,需要處理哪個消息就注冊哪個消息的處理程序。但一開始的時候不是這樣的,開始的時候要手動判斷消息類型,就像:

 
     
       Token = ;
         =  signature = context.Request[ timestamp = context.Request[ nonce = context.Request[ (WeiXin.CheckSignature(signature, timestamp, nonce, Token))
 replyMsg = WeiXin.ReplyMsg((recEvtMsg) => msg = recEvtMsg  RecTextMsg; 
                                 =  + evtMsg = recEvtMsg  EventBaseMsg;
                                 msg = evtMsg  EventAttendMsg;
                                         = 
 xml =
  

做優化的時候,先是試著看能不能在MsgType和MyEventType上做文章,比如注冊時傳入MsgType和處理程序(lamba)兩個參數:

   RegisterMsgHandler(MsgType type, Func<RecEventBaseMsg, ReplyBaseMsg>
}

 這樣的確是可以行的通的,但是在調用SDK注冊的時候還是要手動轉換類型:

 WeiXin.RegisterMsgHandler(MsgType.text, (recEvtMsg) => msg = recEvtMsg   ReplyTextMsg { Content =  +

 那麼能不能每個子類型寫一個呢?

       RegisterMsgHandler(MsgType type, Func<RecTextMsg, ReplyBaseMsg>
   RegisterMsgHandler(MsgType type, Func<, ReplyBaseMsg>

 定義是可以的,來看看調用:

RegisterMsgHandler(MsgType.text,  Func<RecTextMsg, ReplyBaseMsg>((msg) =>  ReplyTextMsg { Content =  +
RegisterMsgHandler(MsgType.text,  Func<RecImageMsg, ReplyBaseMsg>((msg) =>  ReplyTextMsg { Content =  +
RegisterMsgHandler(MsgType.text, (msg) =>  ReplyTextMsg { Content =  +
RegisterMsgHandler(MsgType.text, (msg) =>  ReplyTextMsg { Content =  +
RegisterMsgHandler(MsgType.text, (msg) =>  ReplyTextMsg { Content = 

 從上面調用可知,想用這種方法調用,就不能隨意的用lamba表達式,我所不欲也!最後,終於用泛型搞定了

   RegisterMsgHandler<TMsg>(Func<TMsg, ReplyBaseMsg> handler)  type =  key =  (type == =  (type == =  (type == =  (type == =  (type == =  (type == == (Func<RecEventBaseMsg, ReplyBaseMsg>

經過這樣的變換,我們才可以像開始那樣用簡潔的lamba表達式注冊。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved