C#開(kāi)發(fā)微信門(mén)戶及應(yīng)用(6)--微信門(mén)戶菜單的管理操作

前面幾篇繼續(xù)了我自己對(duì)于C#開(kāi)發(fā)微信門(mén)戶及應(yīng)用的技術(shù)探索和相關(guān)的經(jīng)驗(yàn)總結(jié),繼續(xù)探索微信API并分享相關(guān)的技術(shù),一方面是為了和大家對(duì)這方面進(jìn)行互動(dòng)溝通,另一方面也是專心做好微信應(yīng)用的底層技術(shù)開(kāi)發(fā),把基礎(chǔ)模塊夯實(shí),在未來(lái)的應(yīng)用中派上用途。本隨筆繼續(xù)介紹微信門(mén)戶菜單的管理操作。

1、菜單的基礎(chǔ)信息

微信門(mén)戶的菜單,一般服務(wù)號(hào)和訂閱號(hào)都可以擁有這個(gè)模塊的開(kāi)發(fā),但是訂閱號(hào)好像需要認(rèn)證后才能擁有,而服務(wù)號(hào)則不需要認(rèn)證就可以擁有了。這個(gè)菜單可以有編輯模式和開(kāi)發(fā)模式,編輯模式主要就是在微信門(mén)戶的平臺(tái)上,對(duì)菜單進(jìn)行編輯;而開(kāi)發(fā)模式,就是用戶可以通過(guò)調(diào)用微信的API對(duì)菜單進(jìn)行定制開(kāi)發(fā),通過(guò)POST數(shù)據(jù)到微信服務(wù)器,從而生成對(duì)應(yīng)的菜單內(nèi)容。本文主要介紹基于開(kāi)發(fā)模式的菜單管理操作。
自定義菜單能夠幫助公眾號(hào)豐富界面,讓用戶更好更快地理解公眾號(hào)的功能。目前自定義菜單最多包括3個(gè)一級(jí)菜單,每個(gè)一級(jí)菜單最多包含5個(gè)二級(jí)菜單。一級(jí)菜單最多4個(gè)漢字,二級(jí)菜單最多7個(gè)漢字,多出來(lái)的部分將會(huì)以“...”代替。目前自定義菜單接口可實(shí)現(xiàn)兩種類型按鈕,如下:

click:用戶點(diǎn)擊click類型按鈕后,微信服務(wù)器會(huì)通過(guò)消息接口推送消息類型為event 的結(jié)構(gòu)給開(kāi)發(fā)者(參考消息接口指南),并且?guī)习粹o中開(kāi)發(fā)者填寫(xiě)的key值,開(kāi)發(fā)者可以通過(guò)自定義的key值與用戶進(jìn)行交互;view:用戶點(diǎn)擊view類型按鈕后,微信客戶端將會(huì)打開(kāi)開(kāi)發(fā)者在按鈕中填寫(xiě)的url值 (即網(wǎng)頁(yè)鏈接),達(dá)到打開(kāi)網(wǎng)頁(yè)的目的,建議與網(wǎng)頁(yè)授權(quán)獲取用戶基本信息接口結(jié)合,獲得用戶的登入個(gè)人信息。
菜單提交的數(shù)據(jù),本身是一個(gè)Json的數(shù)據(jù)字符串,它的官方例子數(shù)據(jù)如下所示。

{
 "button":[
 {    
      "type":"click",
      "name":"今日歌曲",
      "key":"V1001_TODAY_MUSIC"
  },
  {
       "type":"click",
       "name":"歌手簡(jiǎn)介",
       "key":"V1001_TODAY_SINGER"
  },
  {
       "name":"菜單",
       "sub_button":[
       {    
           "type":"view",
           "name":"搜索",
           "url":"http://www.soso.com/"
        },
        {
           "type":"view",
           "name":"視頻",
           "url":"http://v.qq.com/"
        },
        {
           "type":"click",
           "name":"贊一下我們",
           "key":"V1001_GOOD"
        }]
   }]
}

從上面我們可以看到,菜單不同的type類型,有不同的字段內(nèi)容,如type為view的有url屬性,而type為click的,則有key屬性。而菜單可以有子菜單sub_button屬性,總得來(lái)說(shuō),為了構(gòu)造好對(duì)應(yīng)的菜單實(shí)體類信息,不是一下就能分析的出來(lái)。

2、菜單的實(shí)體類定義

我看過(guò)一些微信接口的開(kāi)發(fā)代碼,把菜單的分為了好多個(gè)實(shí)體類,指定了繼承關(guān)系,然后分別對(duì)他們進(jìn)行屬性的配置,大概的關(guān)系如下所示。



這種多層關(guān)系的繼承方式能解決問(wèn)題,不過(guò)我覺(jué)得并不是優(yōu)雅的解決方案。其實(shí)結(jié)合Json.NET自身的Attribute屬性配置,可以指定那些為空的內(nèi)容在序列號(hào)為Json字符串的時(shí)候,不顯示出來(lái)的。

[JsonProperty( NullValueHandling = NullValueHandling.Ignore)]

有了這個(gè)屬性,我們就可以統(tǒng)一定義菜單的實(shí)體類信息更多的屬性了,可以把View類型和Click類型的菜單屬性的url和key合并在一起。

/// <summary>
/// 菜單基本信息
/// </summary>
public class MenuInfo
{
    /// <summary>
    /// 按鈕描述,既按鈕名字,不超過(guò)16個(gè)字節(jié),子菜單不超過(guò)40個(gè)字節(jié)
    /// </summary>
    public string name { get; set; }

    /// <summary>
    /// 按鈕類型(click或view)
    /// </summary>
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public string type { get; set; }

    /// <summary>
    /// 按鈕KEY值,用于消息接口(event類型)推送,不超過(guò)128字節(jié)
    /// </summary>
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public string key { get; set; }

    /// <summary>
    /// 網(wǎng)頁(yè)鏈接,用戶點(diǎn)擊按鈕可打開(kāi)鏈接,不超過(guò)256字節(jié)
    /// </summary>
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public string url { get; set; }

    /// <summary>
    /// 子按鈕數(shù)組,按鈕個(gè)數(shù)應(yīng)為2~5個(gè)
    /// </summary>
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public List<MenuInfo> sub_button { get; set; }

.......

但是,這么多信息,不同的類型我需要指定不同的屬性類型,那不是挺麻煩,萬(wàn)一我在View類型的菜單里面,把key屬性設(shè)置了,那怎么辦?

解決方法就是我們定義幾個(gè)構(gòu)造函數(shù),分別用來(lái)構(gòu)造不同的菜單信息,如下所示是對(duì)菜單不同的類型,賦值給不同的屬性的構(gòu)造函數(shù)。

/// <summary>
/// 參數(shù)化構(gòu)造函數(shù)
/// </summary>
/// <param name="name">按鈕名稱</param>
/// <param name="buttonType">菜單按鈕類型</param>
/// <param name="value">按鈕的鍵值(Click),或者連接URL(View)</param>
public MenuInfo(string name, ButtonType buttonType, string value)
{
    this.name = name;
    this.type = buttonType.ToString();

    if (buttonType == ButtonType.click)
    {
        this.key = value;
    }
    else if(buttonType == ButtonType.view)
    {
        this.url = value;
    }
}

好了,還有另外一個(gè)問(wèn)題,子菜單也就是屬性sub_button是可有可無(wú)的東西,有的話,需要指定Name屬性,并添加它的sub_button集合對(duì)象就可以了,那么我們?cè)谠黾右粋€(gè)構(gòu)造子菜單的對(duì)象信息的構(gòu)造函數(shù)。

/// <summary>
/// 參數(shù)化構(gòu)造函數(shù),用于構(gòu)造子菜單
/// </summary>
/// <param name="name">按鈕名稱</param>
/// <param name="sub_button">子菜單集合</param>
public MenuInfo(string name, IEnumerable<MenuInfo> sub_button)
{
    this.name = name;
    this.sub_button = new List<MenuInfo>();
    this.sub_button.AddRange(sub_button);
}

由于只指定Name和sub_button的屬性內(nèi)容,其他內(nèi)容為null的話,自然構(gòu)造出來(lái)的Json就沒(méi)有包含它們,非常完美!

為了獲取菜單的信息,我們還需要定義兩個(gè)實(shí)體對(duì)象,如下所示。

/// <summary>
/// 菜單的Json字符串對(duì)象
/// </summary>
public class MenuJson
{
    public List<MenuInfo> button { get; set; }

    public MenuJson()
    {
        button = new List<MenuInfo>();
    }
}

/// <summary>
/// 菜單列表的Json對(duì)象
/// </summary>
public class MenuListJson
{
    public MenuJson menu { get; set; }
}

3、菜單管理操作的接口實(shí)現(xiàn)

我們從微信的定義里面,可以看到,我們通過(guò)API可以獲取菜單信息、創(chuàng)建菜單、刪除菜單,那么我們來(lái)定義它們的接口如下。

/// <summary>
/// 菜單的相關(guān)操作
/// </summary>
public interface IMenuApi
{              
    /// <summary>
    /// 獲取菜單數(shù)據(jù)
    /// </summary>
    /// <param name="accessToken">調(diào)用接口憑證</param>
    /// <returns></returns>
    MenuJson GetMenu(string accessToken);
                   
    /// <summary>
    /// 創(chuàng)建菜單
    /// </summary>
    /// <param name="accessToken">調(diào)用接口憑證</param>
    /// <param name="menuJson">菜單對(duì)象</param>
    /// <returns></returns>
    CommonResult CreateMenu(string accessToken, MenuJson menuJson);
                   
    /// <summary>
    /// 刪除菜單
    /// </summary>
    /// <param name="accessToken">調(diào)用接口憑證</param>
    /// <returns></returns>
    CommonResult DeleteMenu(string accessToken);
}

具體的獲取菜單信息的實(shí)現(xiàn)如下。

/// <summary>
/// 獲取菜單數(shù)據(jù)
/// </summary>
/// <param name="accessToken">調(diào)用接口憑證</param>
/// <returns></returns>
public MenuJson GetMenu(string accessToken)
{
    MenuJson menu = null;

    var url = string.Format("https://api.weixin.qq.com/cgi-bin/menu/get?access_token={0}", accessToken);
    MenuListJson list = JsonHelper<MenuListJson>.ConvertJson(url);
    if (list != null)
    {
        menu = list.menu;
    }
    return menu;
}

這里就是把返回的Json數(shù)據(jù),統(tǒng)一轉(zhuǎn)換為我們需要的實(shí)體信息了,一步到位。

調(diào)用代碼如下所示。

private void btnGetMenuJson_Click(object sender, EventArgs e)
{
    IMenuApi menuBLL = new MenuApi();
    MenuJson menu = menuBLL.GetMenu(token);
    if (menu != null)
    {
        Console.WriteLine(menu.ToJson());
    }
}

創(chuàng)建和刪除菜單對(duì)象的操作實(shí)現(xiàn)如下所示。

/// <summary>
/// 創(chuàng)建菜單
/// </summary>
/// <param name="accessToken">調(diào)用接口憑證</param>
/// <param name="menuJson">菜單對(duì)象</param>
/// <returns></returns>
public CommonResult CreateMenu(string accessToken, MenuJson menuJson)
{
    var url = string.Format("https://api.weixin.qq.com/cgi-bin/menu/create?access_token={0}", accessToken);
    string postData = menuJson.ToJson();

    return Helper.GetExecuteResult(url, postData);
}
        
/// <summary>
/// 刪除菜單
/// </summary>
/// <param name="accessToken">調(diào)用接口憑證</param>
/// <returns></returns>
public CommonResult DeleteMenu(string accessToken)
{
    var url = string.Format("https://api.weixin.qq.com/cgi-bin/menu/delete?access_token={0}", accessToken);

    return Helper.GetExecuteResult(url);
}

看到這里,有些人可能會(huì)問(wèn),實(shí)體類你簡(jiǎn)化了,那么創(chuàng)建菜單是不是挺麻煩的,特別是構(gòu)造對(duì)應(yīng)的信息應(yīng)該如何操作呢?前面不是介紹了不同的構(gòu)造函數(shù)了嗎,通過(guò)他們簡(jiǎn)單就搞定了,不用記下太多的實(shí)體類及它們的繼承關(guān)系來(lái)處理菜單信息。

private void btnCreateMenu_Click(object sender, EventArgs e)
{                       
    MenuInfo productInfo = new MenuInfo("軟件產(chǎn)品", new MenuInfo[] { 
        new MenuInfo("病人資料管理系統(tǒng)", ButtonType.click, "patient"), 
        new MenuInfo("客戶關(guān)系管理系統(tǒng)", ButtonType.click, "crm"), 
        new MenuInfo("酒店管理系統(tǒng)", ButtonType.click, "hotel"), 
        new MenuInfo("送水管理系統(tǒng)", ButtonType.click, "water")
    });                                    

    MenuInfo frameworkInfo = new MenuInfo("框架產(chǎn)品", new MenuInfo[] { 
        new MenuInfo("Win開(kāi)發(fā)框架", ButtonType.click, "win"),
        new MenuInfo("WCF開(kāi)發(fā)框架", ButtonType.click, "wcf"),
        new MenuInfo("混合式框架", ButtonType.click, "mix"), 
        new MenuInfo("Web開(kāi)發(fā)框架", ButtonType.click, "web"),
        new MenuInfo("代碼生成工具", ButtonType.click, "database2sharp")
    });

    MenuInfo relatedInfo = new MenuInfo("相關(guān)鏈接", new MenuInfo[] { 
        new MenuInfo("公司介紹", ButtonType.click, "Event_Company"),
        new MenuInfo("官方網(wǎng)站", ButtonType.view, "http://www.iqidi.com"),
        new MenuInfo("提點(diǎn)建議", ButtonType.click, "Event_Suggestion"),
        new MenuInfo("聯(lián)系客服", ButtonType.click, "Event_Contact"),
        new MenuInfo("發(fā)郵件", ButtonType.view, "http://mail.qq.com/cgi-bin/qm_share?t=qm_mailme&email=S31yfX15fn8LOjplKCQm")
    });

    MenuJson menuJson = new MenuJson();
    menuJson.button.AddRange(new MenuInfo[] { productInfo, frameworkInfo, relatedInfo });

    //Console.WriteLine(menuJson.ToJson());

    if (MessageUtil.ShowYesNoAndWarning("您確認(rèn)要?jiǎng)?chuàng)建菜單嗎") == System.Windows.Forms.DialogResult.Yes)
    {
        IMenuApi menuBLL = new MenuApi();
        CommonResult result = menuBLL.CreateMenu(token, menuJson);
        Console.WriteLine("創(chuàng)建菜單:" + (result.Success ? "成功" : "失敗:" + result.ErrorMessage));
    }
}

這個(gè)就是我微信門(mén)戶里面的菜單操作了,具體效果可以關(guān)注我的微信門(mén)戶:廣州愛(ài)奇迪,也可以掃描下面二維碼進(jìn)行關(guān)注了解。



菜單的效果如下:


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容