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

来源:http://www.cnblogs.com/wuhuacong/archive/2016/04/08/5370295.html
-Advertisement-
Play Games

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


在很多場合下,我們可能需要利用微信公眾號的優勢,定期給指定用戶群發送一些推廣消息或者新聞內容,以便給關註客戶一種經常更新公眾號內容的感覺,同時也方便我們經常和用戶進行互動。微信公眾號的高級群發介面就是為了處理這個場景的,本文介紹在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)--開始使用微信介面

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • .NET CORE的官方(http://dotnet.github.io/getting-started/)只提供了Windows, Ubuntu14.04, 及Docker(也是基於Ubuntu14.04做的Image). 但鑒於微軟已經把RedHat做為參考平臺而且用Ubuntu14.04做Se ...
  • SCP服務實現Linux交互 在實際工作中,我們可以使用scp伺服器進行Linux與Linux之間的信息交互。 基本指令: scp 本地文件 遠程文件 scp 遠程文件 本地文件 scp –r 文件夾 文件夾 scp –P 埠 文件 文件 例1:上傳文件到其... ...
  • tcp簡單實驗 server.c #include /* See NOTES */ #include #include #include #include #include #include #include #include /*socket * bind * listen * accept * ... ...
  • 其實之前也有提及過,Cypress公司提供的官方文件和應用手冊真的可以解決很多問題。做的也很人性化,操作也及其簡單,幾乎只要在 TD_int()裡面配置一些常用的參數即可,其他都可以不用操作。 作為一個常用查詢手冊吧!!!! 《EZ-USB一些重要寄存器的配置》博客中已經提及過相關寄存器的配置,那麼 ...
  • 簡介: LVM ( Logical Volume Manager ) 邏輯捲管理 一、創建 LV 1、首先在你的虛擬機上添加一塊新的硬碟用來做實驗。 2、安裝 lvm : yum -y install lvm2 3、查看新添加的磁碟 ## 其中,/dev/sdb 就是我新添加的磁碟了 4、創建物理分 ...
  • 有這樣的兩個集合: string[] bigArr = new string[] { "a", "b", "c" };string[] smallArr = new string[] { "a", "b"}; 現在需要判斷smallArr是否是bigArr的子集。只要拿著bigArray和small ...
  • 用途:簡化代碼 說明: int a; //a<>null int ?b; //b=null int ?c = b+1; //c=null; int?a=null; int b;(聲明a和b) b=a??2; //b=2; a=6;b=a??8;//b=6; int a=1>0?1:0 //a=1; ...
  • 通過分析源碼可以更好理解List<T>的工作方式,幫助我們寫出更穩定的代碼。 List<T>源碼地址: https://github.com/dotnet/corefx/blob/master/src/System.Collections/src/System/Collections/Generic ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...