程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#開發微信門戶及應用(30)--消息的群發處理和預覽功能,

C#開發微信門戶及應用(30)--消息的群發處理和預覽功能,

編輯:C#入門知識

C#開發微信門戶及應用(30)--消息的群發處理和預覽功能,


在很多場合下,我們可能需要利用微信公眾號的優勢,定期給指定用戶群發送一些推廣消息或者新聞內容,以便給關注客戶一種經常更新公眾號內容的感覺,同時也方便我們經常和用戶進行互動。微信公眾號的高級群發接口就是為了處理這個場景的,本文介紹在C#代碼中如何封裝消息的群發和預覽等功能。

1、消息群發的功能和限制

對於公眾號中的服務號和訂閱號,群發的消息有一定的限制,具體規則如下所示。

1、對於認證訂閱號,群發接口每天可成功調用1次,此次群發可選擇發送給全部用戶或某個分組;
2、對於認證服務號雖然開發者使用高級群發接口的每日調用限制為100次,但是用戶每月只能接收4條,無論在公眾平台網站上,還是使用接口群發,用戶每月只能接收4條群發消息,多於4條的群發將對該用戶發送失敗;
3、具備微信支付權限的公眾號,在使用群發接口上傳、群發圖文消息類型時,可使用<a>標簽加入外鏈;
4、開發者可以使用預覽接口校對消息樣式和排版,通過預覽接口可發送編輯好的消息給指定用戶校驗效果。

群發圖文消息的過程如下:

1、首先,預先將圖文消息中需要用到的圖片,使用上傳圖文消息內圖片接口,上傳成功並獲得圖片URL
2、上傳圖文消息素材,需要用到圖片時,請使用上一步獲取的圖片URL
3、使用對用戶分組的群發,或對OpenID列表的群發,將圖文消息群發出去
4、在上述過程中,如果需要,還可以預覽圖文消息、查詢群發狀態,或刪除已群發的消息等

群發圖片、文本等其他消息類型的過程如下:

1、如果是群發文本消息,則直接根據下面的接口說明進行群發即可
2、如果是群發圖片、視頻等消息,則需要預先通過素材管理接口准備好mediaID

 2、消息的群發處理

 雖然群發的消息類型有幾種,如包括圖文消息、文本消息、圖片、視頻、語音、卡劵等等,不過消息群發方式分為兩類:根據群組發送消息和根據OpenID發送消息兩種。

根據微信接口的定義,我們設計了對上面兩種不同方式的發送接口,我們把不同類型的消息放到枚舉MassMessageType 進行定義。

        /// <summary>
        /// 根據分組進行群發消息(圖文消息、文本消息、語音消息、視頻消息、圖片、卡劵等)
        /// </summary>
        /// <param name="accessToken">訪問憑證</param>
        /// <param name="mediaIdOrContent">群發媒體文件時傳入mediaId,群發文本消息時傳入content,群發卡券時傳入cardId</param>
        /// <param name="groupId">群發到的分組的group_id</param>
        /// <param name="isToAll">
        /// 使用is_to_all為true且成功群發,會使得此次群發進入歷史消息列表。
        /// 設置is_to_all為false時是可以多次群發的,但每個用戶只會收到最多4條,且這些群發不會進入歷史消息列表</param>
        /// <returns></returns>
        MassMessageResult SendByGroup(string accessToken, MassMessageType messageType, string mediaIdOrContent, string groupId, bool isToAll = false);

        /// <summary>
        /// 根據OpenId進行群發消息(視頻消息需要單獨)
        /// </summary>
        /// <param name="accessToken">訪問憑證</param>
        /// <param name="messageType">消息類型</param>
        /// <param name="mediaIdOrContent">用於群發的消息的media_id</param>
        /// <param name="openIdList">openId字符串數組</param>        
        /// <returns></returns>
        MassMessageResult SendByOpenId(string accessToken, MassMessageType messageType, string mediaIdOrContent, List<string> openIdList);

其中枚舉MassMessageType定義代碼如下所示。

   /// <summary>
    /// 群發消息的類型
    /// </summary>
    public enum MassMessageType
    {
        /// <summary>
        /// 圖文消息
        /// </summary>
        mpnews,

        /// <summary>
        /// 文本消息
        /// </summary>
        text,

        /// <summary>
        /// 圖片
        /// </summary>
        image,

        /// <summary>
        /// 語音
        /// </summary>
        voice,

        /// <summary>
        /// 音樂
        /// </summary>
        music,

        /// <summary>
        /// 視頻
        /// </summary>
        video,

        /// <summary>
        /// 卡劵
        /// </summary>
        wxcard
    }

然後我們根據上面的接口實現相關的處理函數,群發消息的類定義代碼如下所示。

    /// <summary>
    /// 消息群發.
    /// 在公眾平台網站上,為訂閱號提供了每天1條的群發權限,為服務號提供每月(自然月)4條的群發權限。
    /// 而對於某些具備開發能力的公眾號運營者,可以通過高級群發接口,實現更靈活的群發能力。
    /// </summary>
    public class MassSendApi : IMassSendApi

對於圖文消息的群發規則,微信接口定義如下。

接口調用請求說明

http請求方式: POST
https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token=ACCESS_TOKEN

POST數據說明

POST數據示例如下:

圖文消息(注意圖文消息的media_id需要通過上述方法來得到):

{
   "filter":{
      "is_to_all":false,
      "group_id":2
   },
   "mpnews":{
      "media_id":"123dsdajkasd231jhksad"
   },
    "msgtype":"mpnews"
}

其他類似文本消息、圖片、視頻、語音、卡劵等發送方式類似,都是提供一個不同的JSON字符串,然後提交到對應的連接地址就可以了,因此我們可以把它們進行統一的封裝處理。

我們可以在一個條件語句裡面對內容進行組裝,例如對於圖文消息的處理代碼如下所示。

switch (messageType)
            {
                case MassMessageType.mpnews://圖文消息
                    postData = new
                    {
                        filter = new
                        {
                            is_to_all = isToAll, //是否讓此次群發進入歷史消息列表
                            group_id = groupId //群發到的分組的group_id
                        },
                        mpnews = new
                        {
                            media_id = mediaIdOrContent  //用於群發的消息的media_id
                        },
                        msgtype = "mpnews"
                    }.ToJson();
                    break;

對於文本消息的組裝如下所示。

                case MassMessageType.text://文本消息
                    postData = new
                    {
                        filter = new
                        {
                            is_to_all = isToAll, //是否讓此次群發進入歷史消息列表
                            group_id = groupId //群發到的分組的group_id
                        },
                        text = new
                        {
                            content = mediaIdOrContent  //用於群發的消息的內容
                        },
                        msgtype = "text"
                    }.ToJson();
                    break;

最後我們通過代碼進行提交JSON數據,並獲取返回結果即可,如下代碼所示。

            string url = string.Format("https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token={0}", accessToken);

            MassMessageResult result = JsonHelper<MassMessageResult>.ConvertJson(url, postData);
            return result;

這樣,整合各個消息類型的處理,我們就可以得到一個完整的消息群發操作了。

群發給openid的操作也是類似上面的處理方式,也是通過一個switch的條件語句,進行不同內容的構建,然後統一發送即可。

請注意:在返回成功時,意味著群發任務提交成功,並不意味著此時群發已經結束,所以,仍有可能在後續的發送過程中出現異常情況導致用戶未收到消息,如消息有時會進行審核、服務器不穩定等。此外,群發任務一般需要較長的時間才能全部發送完畢,請耐心等待

由於群發任務提交後,群發任務可能在一定時間後才完成,因此,群發接口調用時,僅會給出群發任務是否提交成功的提示,若群發任務提交成功,則在群發任務結束時,會向開發者在公眾平台填寫的開發者URL(callback URL)推送事件。

推送的XML結構如下(發送成功時):

<xml>
<ToUserName><![CDATA[gh_3e8adccde292]]></ToUserName>
<FromUserName><![CDATA[oR5Gjjl_eiZoUpGozMo7dbBJ362A]]></FromUserName>
<CreateTime>1394524295</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[MASSSENDJOBFINISH]]></Event>
<MsgID>1988</MsgID>
<Status><![CDATA[sendsuccess]]></Status>
<TotalCount>100</TotalCount>
<FilterCount>80</FilterCount>
<SentCount>75</SentCount>
<ErrorCount>5</ErrorCount>
</xml>

對應的字段說明如下所示。

參數說明 ToUserName 公眾號的微信號 FromUserName 公眾號群發助手的微信號,為mphelper CreateTime 創建時間的時間戳 MsgType 消息類型,此處為event Event 事件信息,此處為MASSSENDJOBFINISH MsgID 群發的消息ID Status 群發的結構,為“send success”或“send fail”或“err(num)”。但send success時,也有可能因用戶拒收公眾號的消息、系統錯誤等原因造成少量用戶接收失敗。err(num)是審核失敗的具體原因 TotalCount group_id下粉絲數;或者openid_list中的粉絲數 FilterCount 過濾(過濾是指特定地區、性別的過濾、用戶設置拒收的過濾,用戶接收已超4條的過濾)後,准備發送的粉絲數,原則上,FilterCount = SentCount + ErrorCount SentCount 發送成功的粉絲數 ErrorCount 發送失敗的粉絲數

因此我們需要通過處理消息群發的發送完成操作,定義一個實體類來承載這個消息。

    public class RequestMassSendJobFinish : BaseEvent
    {
        public RequestMassSendJobFinish()
        {
            this.MsgType = RequestMsgType.Event.ToString().ToLower();
            this.Event = RequestEvent.MASSSENDJOBFINISH.ToString();
        }

        /// <summary>
        /// 群發的消息ID
        /// </summary>
        public int MsgID { get; set; }

        /// <summary>
        /// 返回狀態。
        /// </summary>
        public string Status { get; set; }

        /// <summary>
        /// group_id下粉絲數;或者openid_list中的粉絲數
        /// </summary>
        public int TotalCount { get; set; }

        /// <summary>
        /// 過濾(過濾是指,有些用戶在微信設置不接收該公眾號的消息)後,准備發送的粉絲數,原則上,FilterCount = SentCount + ErrorCount
        /// </summary>
        public int FilterCount { get; set; }

        /// <summary>
        /// 發送成功的粉絲數
        /// </summary>
        public int SendCount { get; set; }

        /// <summary>
        /// 發送失敗的粉絲數
        /// </summary>
        public int ErrorCount { get; set; }
    }

在我們需要記錄或者更新處理這種群發消息的狀態的時候,我們可以在整個微信的消息鏈裡面對這樣的請求事件進行處理,如下代碼是處理這種群發消息的通知的。

                            case RequestEvent.MASSSENDJOBFINISH:
                                {
                                    //由於群發任務徹底完成需要較長時間,將會在群發任務即將完成的時候,就推送群發結果,此時的推送人數數據將會與實際情形存在一定誤差
                                    RequestMassSendJobFinish info = XmlConvertor.XmlToObject(postStr, typeof(RequestMassSendJobFinish)) as RequestMassSendJobFinish;
                                    if(info != null)
                                    {
                                        //在此記錄群發完成的處理
                                    }
                                    LogTextHelper.Info(eventName + ((info == null) ? "info is null" : info.ToJson()));
                                }
                                break;

 

3、待群發消息的預覽

在很多時候,我們群發消息之前,我們希望通過自己的微信號來看看具體的群發消息效果,如果沒有問題我們在統一群發,相當於一個真實的審核過程,這樣對於我們發送高質量的消息是一個很好的習慣。

對於普通的消息預覽,我們定義的接口如下所示。

        /// <summary>
        /// 預覽接口【訂閱號與服務號認證後均可用】。
        /// 開發者可通過該接口發送消息給指定用戶,在手機端查看消息的樣式和排版。
        /// 為了滿足第三方平台開發者的需求,在保留對openID預覽能力的同時,增加了對指定微信號發送預覽的能力,但該能力每日調用次數有限制(100次),請勿濫用。
        /// </summary>
        /// <param name="accessToken">訪問憑證</param>
        /// <param name="messageType">消息類型</param>
        /// <param name="media_id">用於群發的消息的media_id</param>
        /// <param name="touserOpenId">接收消息用戶對應該公眾號的openid</param>
        /// <param name="towxname">可以針對微信號進行預覽(而非openID),towxname和touser同時賦值時,以towxname優先</param>
        /// <returns></returns>
        MassMessageResult PreviewMessage(string accessToken, MassMessageType messageType, string media_id, string touserOpenId, string towxname = null);

具體的實現也就是針對不同的消息類型,構建一個不同的處理機制,把它們差異性的JSON構造出來,然後統一調用就可以了,具體代碼如下所示。

        public MassMessageResult PreviewMessage(string accessToken, MassMessageType messageType, string media_id, string touserOpenId, string towxname = null)
        {
            string postData = "";
            switch (messageType)
            {
                case MassMessageType.mpnews://圖文消息
                    postData = new
                    {
                        touser = touserOpenId,
                        towxname = towxname,
                        mpnews = new
                        {
                            media_id = media_id
                        },
                        msgtype = "mpnews"
                    }.ToJson();
                    break;

                case MassMessageType.text://文本消息
                    postData = new
                    {
                        touser = touserOpenId,
                        towxname = towxname,
                        text = new
                        {
                            content = media_id
                        },
                        msgtype = "text"
                    }.ToJson();
                    break;

                case MassMessageType.voice://語音
                    postData = new
                    {
                        touser = touserOpenId,
                        towxname = towxname,
                        voice = new
                        {
                            media_id = media_id
                        },
                        msgtype = "voice"
                    }.ToJson();
                    break;

                case MassMessageType.image://圖片
                    postData = new
                    {
                        touser = touserOpenId,
                        towxname = towxname,
                        image = new
                        {
                            media_id = media_id
                        },
                        msgtype = "image"
                    }.ToJson();
                    break;

                case MassMessageType.video://視頻
                    postData = new
                    {
                        touser = touserOpenId,
                        towxname = towxname,
                        mpvideo = new
                        {
                            media_id = media_id
                        },
                        msgtype = "mpvideo"
                    }.ToJson();
                    break;

                case MassMessageType.wxcard: //卡劵
                    throw new WeixinException("發送卡券息請使用PreviewCardMessage方法。");
                    break;
            }

            var url = string.Format("https://api.weixin.qq.com/cgi-bin/message/mass/preview?access_token={0}", accessToken);
            return JsonHelper<MassMessageResult>.ConvertJson(url, postData);
        }

消息的預覽在我們正式群發消息前的審核是比較有用的,我們可以通過接口進行一個消息的預覽,可以在微信公眾號上看到的效果與正式群發後的消息是一樣的。

例如我們通過下面的代碼進行一個簡單的預覽消息操作。

        /// <summary>
        /// 群發消息的預覽
        /// </summary>
        private void btnPreviewMass_Click(object sender, EventArgs e)
        {
            //上傳圖片
            btnUpload_Click(null, null);

            //上傳圖文消息
            btnUploadNews_Click(null, null);

            //消息群發前的預覽操作
            List<string> list = new List<string>() { openId };
            IMassSendApi api = new MassSendApi();
            var mediaId = this.news_mediaId;
            MassMessageResult result = api.PreviewMessage(token, MassMessageType.mpnews, mediaId, openId);
            if (result != null)
            {
                Console.WriteLine(result.msg_id);
            }
        }

最後可以看到例子代碼的預覽效果如下所示。

 

如果對這個《C#開發微信門戶及應用》系列感興趣,可以關注我的其他文章,系列隨筆如下所示:

C#開發微信門戶及應用(29)--微信個性化菜單的實現

C#開發微信門戶及應用(28)--微信“搖一搖·周邊”功能的使用和接口的實現

C#開發微信門戶及應用(27)-公眾號模板消息管理 

C#開發微信門戶及應用(26)-公眾號微信素材管理

C#開發微信門戶及應用(25)-微信企業號的客戶端管理功能

C#開發微信門戶及應用(24)-微信小店貨架信息管理

C#開發微信門戶及應用(23)-微信小店商品管理接口的封裝和測試

C#開發微信門戶及應用(22)-微信小店的開發和使用

C#開發微信門戶及應用(21)-微信企業號的消息和事件的接收處理及解密 

C#開發微信門戶及應用(20)-微信企業號的菜單管理

C#開發微信門戶及應用(19)-微信企業號的消息發送(文本、圖片、文件、語音、視頻、圖文消息等)

C#開發微信門戶及應用(18)-微信企業號的通訊錄管理開發之成員管理

C#開發微信門戶及應用(17)-微信企業號的通訊錄管理開發之部門管理

C#開發微信門戶及應用(16)-微信企業號的配置和使用

C#開發微信門戶及應用(15)-微信菜單增加掃一掃、發圖片、發地理位置功能

 C#開發微信門戶及應用(14)-在微信菜單中采用重定向獲取用戶數據

C#開發微信門戶及應用(13)-使用地理位置擴展相關應用

C#開發微信門戶及應用(12)-使用語音處理

C#開發微信門戶及應用(11)--微信菜單的多種表現方式介紹

C#開發微信門戶及應用(10)--在管理系統中同步微信用戶分組信息

C#開發微信門戶及應用(9)-微信門戶菜單管理及提交到微信服務器

C#開發微信門戶及應用(8)-微信門戶應用管理系統功能介紹

C#開發微信門戶及應用(7)-微信多客服功能及開發集成

C#開發微信門戶及應用(6)--微信門戶菜單的管理操作

C#開發微信門戶及應用(5)--用戶分組信息管理

C#開發微信門戶及應用(4)--關注用戶列表及詳細信息管理

C#開發微信門戶及應用(3)--文本消息和圖文消息的應答

C#開發微信門戶及應用(2)--微信消息的處理和應答

C#開發微信門戶及應用(1)--開始使用微信接口

 

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