http://www.cnblogs.com/wuhuacong/p/3701961.html

前面几篇继续了我自己对于C#开发微信门户及应用的技术探索和相关的经验总结,继续探索微信API并分享相关的技术,一方面是为了和大家对这方面进行互动沟通,另一方面也是专心做好微信应用的底层技术开发,把基础模块夯实,在未来的应用中派上用途。本随笔继续介绍微信门户菜单的管理操作。

1、菜单的基础信息

微信门户的菜单,一般服务号和订阅号都可以拥有这个模块的开发,但是订阅号好像需要认证后才能拥有,而服务号则不需要认证就可以拥有了。这个菜单可以有编辑模式和开发模式,编辑模式主要就是在微信门户的平台上,对菜单进行编辑;而开发模式,就是用户可以通过调用微信的API对菜单进行定制开发,通过POST数据到微信服务器,从而生成对应的菜单内容。本文主要介绍基于开发模式的菜单管理操作。

自定义菜单能够帮助公众号丰富界面,让用户更好更快地理解公众号的功能。目前自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单。一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以“...”代替。目前自定义菜单接口可实现两种类型按钮,如下:

click:
用户点击click类型按钮后,微信服务器会通过消息接口推送消息类型为event 的结构给开发者(参考消息接口指南),并且带上按钮中开发者填写的key值,开发者可以通过自定义的key值与用户进行交互;
view:
用户点击view类型按钮后,微信客户端将会打开开发者在按钮中填写的url值 (即网页链接),达到打开网页的目的,建议与网页授权获取用户基本信息接口结合,获得用户的登入个人信息。

菜单提交的数据,本身是一个Json的数据字符串,它的官方例子数据如下所示。

 {
"button":[
{
"type":"click",
"name":"今日歌曲",
"key":"V1001_TODAY_MUSIC"
},
{
"type":"click",
"name":"歌手简介",
"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类型,有不同的字段内容,如type为view的有url属性,而type为click的,则有key属性。而菜单可以有子菜单sub_button属性,总得来说,为了构造好对应的菜单实体类信息,不是一下就能分析的出来。

2、菜单的实体类定义

我看过一些微信接口的开发代码,把菜单的分为了好多个实体类,指定了继承关系,然后分别对他们进行属性的配置,大概的关系如下所示。

这种多层关系的继承方式能解决问题,不过我觉得并不是优雅的解决方案。其实结合Json.NET自身的Attribute属性配置,可以指定那些为空的内容在序列号为Json字符串的时候,不显示出来的。

[JsonProperty( NullValueHandling = NullValueHandling.Ignore)]

有了这个属性,我们就可以统一定义菜单的实体类信息更多的属性了,可以把View类型和Click类型的菜单属性的url和key合并在一起。

    /// <summary>
/// 菜单基本信息
/// </summary>
public class MenuInfo
{
/// <summary>
/// 按钮描述,既按钮名字,不超过16个字节,子菜单不超过40个字节
/// </summary>
public string name { get; set; } /// <summary>
/// 按钮类型(click或view)
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string type { get; set; } /// <summary>
/// 按钮KEY值,用于消息接口(event类型)推送,不超过128字节
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string key { get; set; } /// <summary>
/// 网页链接,用户点击按钮可打开链接,不超过256字节
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string url { get; set; } /// <summary>
/// 子按钮数组,按钮个数应为2~5个
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public List<MenuInfo> sub_button { get; set; } .......

但是,这么多信息,不同的类型我需要指定不同的属性类型,那不是挺麻烦,万一我在View类型的菜单里面,把key属性设置了,那怎么办?

解决方法就是我们定义几个构造函数,分别用来构造不同的菜单信息,如下所示是对菜单不同的类型,赋值给不同的属性的构造函数。

        /// <summary>
/// 参数化构造函数
/// </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;
}
}

好了,还有另外一个问题,子菜单也就是属性sub_button是可有可无的东西,有的话,需要指定Name属性,并添加它的sub_button集合对象就可以了,那么我们在增加一个构造子菜单的对象信息的构造函数。

        /// <summary>
/// 参数化构造函数,用于构造子菜单
/// </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的属性内容,其他内容为null的话,自然构造出来的Json就没有包含它们,非常完美!

为了获取菜单的信息,我们还需要定义两个实体对象,如下所示。

    /// <summary>
/// 菜单的Json字符串对象
/// </summary>
public class MenuJson
{
public List<MenuInfo> button { get; set; } public MenuJson()
{
button = new List<MenuInfo>();
}
} /// <summary>
/// 菜单列表的Json对象
/// </summary>
public class MenuListJson
{
public MenuJson menu { get; set; }
}

3、菜单管理操作的接口实现

我们从微信的定义里面,可以看到,我们通过API可以获取菜单信息、创建菜单、删除菜单,那么我们来定义它们的接口如下。

    /// <summary>
/// 菜单的相关操作
/// </summary>
public interface IMenuApi
{
/// <summary>
/// 获取菜单数据
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <returns></returns>
MenuJson GetMenu(string accessToken); /// <summary>
/// 创建菜单
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="menuJson">菜单对象</param>
/// <returns></returns>
CommonResult CreateMenu(string accessToken, MenuJson menuJson); /// <summary>
/// 删除菜单
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <returns></returns>
CommonResult DeleteMenu(string accessToken);
}

具体的获取菜单信息的实现如下。

        /// <summary>
/// 获取菜单数据
/// </summary>
/// <param name="accessToken">调用接口凭证</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数据,统一转换为我们需要的实体信息了,一步到位。

调用代码如下所示。

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

创建和删除菜单对象的操作实现如下所示。

        /// <summary>
/// 创建菜单
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="menuJson">菜单对象</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">调用接口凭证</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);
}

看到这里,有些人可能会问,实体类你简化了,那么创建菜单是不是挺麻烦的,特别是构造对应的信息应该如何操作呢?前面不是介绍了不同的构造函数了吗,通过他们简单就搞定了,不用记下太多的实体类及它们的继承关系来处理菜单信息。

        private void btnCreateMenu_Click(object sender, EventArgs e)
{
MenuInfo productInfo = new MenuInfo("软件产品", new MenuInfo[] {
new MenuInfo("病人资料管理系统", ButtonType.click, "patient"),
new MenuInfo("客户关系管理系统", ButtonType.click, "crm"),
new MenuInfo("酒店管理系统", ButtonType.click, "hotel"),
new MenuInfo("送水管理系统", ButtonType.click, "water")
}); MenuInfo frameworkInfo = new MenuInfo("框架产品", new MenuInfo[] {
new MenuInfo("Win开发框架", ButtonType.click, "win"),
new MenuInfo("WCF开发框架", ButtonType.click, "wcf"),
new MenuInfo("混合式框架", ButtonType.click, "mix"),
new MenuInfo("Web开发框架", ButtonType.click, "web"),
new MenuInfo("代码生成工具", ButtonType.click, "database2sharp")
}); MenuInfo relatedInfo = new MenuInfo("相关链接", new MenuInfo[] {
new MenuInfo("公司介绍", ButtonType.click, "Event_Company"),
new MenuInfo("官方网站", ButtonType.view, "http://www.iqidi.com"),
new MenuInfo("提点建议", ButtonType.click, "Event_Suggestion"),
new MenuInfo("联系客服", ButtonType.click, "Event_Contact"),
new MenuInfo("发邮件", 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("您确认要创建菜单吗") == System.Windows.Forms.DialogResult.Yes)
{
IMenuApi menuBLL = new MenuApi();
CommonResult result = menuBLL.CreateMenu(token, menuJson);
Console.WriteLine("创建菜单:" + (result.Success ? "成功" : "失败:" + result.ErrorMessage));
}
}

这个就是我微信门户里面的菜单操作了,具体效果可以关注我的微信门户:广州爱奇迪,也可以扫描下面二维码进行关注了解。

菜单的效果如下:

(转)C#开发微信门户及应用(6)--微信门户菜单的管理操作的更多相关文章

  1. C#开发微信门户及应用(6)--微信门户菜单的管理操作

    前面几篇继续了我自己对于C#开发微信门户及应用的技术探索和相关的经验总结,继续探索微信API并分享相关的技术,一方面是为了和大家对这方面进行互动沟通,另一方面也是专心做好微信应用的底层技术开发,把基础 ...

  2. C#-MVC开发微信应用(4)--微信门户菜单的管理操作

    最近对微信接口进行深入的研究,通过把底层接口一步步进行封装后,逐步升级到自动化配置.自动化应答,以及后台处理界面的优化和完善上,力求搭建一个较为完善.适用的微信门户应用管理系统. 在微信门户系统里面, ...

  3. C#开发微信门户及应用(25)-微信企业号的客户端管理功能

    我们知道,微信公众号和企业号都提供了一个官方的Web后台,方便我们对微信账号的配置,以及相关数据的管理功能,对于微信企业号来说,有通讯录中的组织架构管理.标签管理.人员管理.以及消息的发送等功能,其中 ...

  4. C#开发微信门户及应用(38)--微信摇一摇红包功能

    摇一摇周边红包接口是为线下商户提供的发红包功能.用户可以在商家门店等线下场所通过摇一摇周边领取商家发放的红包.我曾经在<C#开发微信门户及应用(28)--微信“摇一摇·周边”功能的使用和接口的实 ...

  5. C#开发微信门户及应用(37)--微信公众号标签管理功能

    微信公众号,仿照企业号的思路,增加了标签管理的功能,对关注的粉丝可以设置标签管理,实现更加方便的分组管理功能.开发者可以使用用户标签管理的相关接口,实现对公众号的标签进行创建.查询.修改.删除等操作, ...

  6. C#开发微信门户及应用(36)--微信卡劵管理的封装操作

    前面几篇介绍了微信支付方面的内容,本篇继续微信接口的一些其他方面的内容:卡劵管理.卡劵管理是微信接口里面非常复杂的一个部分,里面的接口非常多,我花了不少时间对它进行了封装处理,重构优化等等工作,卡劵在 ...

  7. C#开发微信门户及应用(35)--微信支付之企业付款封装操作

    在前面几篇随笔,都是介绍微信支付及红包相关的内容,其实支付部分的内容还有很多,例如企业付款.公众号支付或刷卡支付.摇一摇红包.代金券等方面的内容,这些都是微信接口支持的内容,本篇继续微信支付这一主题, ...

  8. C#开发微信门户及应用(34)--微信裂变红包

    在上篇随笔<C#开发微信门户及应用(33)--微信现金红包的封装及使用>介绍了普通现金红包的封装和使用,这种红包只能单独一次发给一个人,用户获取了红包就完成了,如果我们让用户收到红包后,可 ...

  9. C#开发微信门户及应用(33)--微信现金红包的封装及使用

    我在上篇随笔<C#开发微信门户及应用(32)--微信支付接入和API封装使用>介绍为微信支付的API封装及使用,其中介绍了如何配置好支付环境,并对扫码支付的两种方式如何在C#开发中使用进行 ...

随机推荐

  1. Grails里的集成测试代码试例

    测试的命令,3和2不一样了,要找找.. User.groovy package com.grailsinaction class User { String loginId String passwo ...

  2. hdu_1039_Easier Done Than Said_201311051511

    Easier Done Than Said? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/O ...

  3. 单点登录cas常见问题(八) - 什么时候会用到代理proxy模式?

    举一个样例:有两个应用App1和App2,它们都是受Casserver保护的,即请求它们时都须要通过Cas server的认证. 如今须要在App1中通过Http请求訪问App2,显然该请求将会被Ap ...

  4. 启动VIP报CRS-1028/CRS-0223致使VIP状态为UNKNOWN故障分析与解决

    CRS版本号为10.2.0.4 1.VIP State为UNKNOWN [root@XXdb1 ~]# crs_stat -t Name           Type           Target ...

  5. luogu1026 统计单词个数

    题目大意 给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个).要求将此字母串分成k份(1< k< =40),且每份中包含 ...

  6. 解决WinForm下ListBox控件“设置DataSource属性后无法修改项集合”

    解决WinForm下ListBox控件“设置DataSource属性后无法修改项集合” 最近更新: 2013-2-15    587   很少写WinForm程序第一次使用ListBox控件就遇到了比 ...

  7. 442C

    贪心 感觉思路很奥妙 首先我们把那些比两边小的数删掉,因为不删的话两边的数就会选这个数,这样就成了先上升后下降的序列,很明显除了第一第二大的数都能选,然后统计就好了. #include<bits ...

  8. 基于Spark ML的Titanic Challenge (Top 6%)

    下面代码按照之前参加Kaggle的python代码改写,只完成了模型的训练过程,还需要对test集的数据进行转换和对test集进行预测. scala 2.11.12 spark 2.2.2 packa ...

  9. 第2课 Git配置文件的妙用

    2-1 "git config"  指令的用法 文件夹中".git"子文件夹内的config文件的优先权>登录账号的home directory中的.gi ...

  10. E20170902-hm

    devise v. 设计; 想出; 发明; 策划;   n. 遗赠; 遗赠的财产; 遗赠的条款; device n. 设备