1. 一、简介
  2.  
  3. 微信公众平台服务号以及之前成功申请内测资格的订阅号都具有自定义菜单的功能。开发者可利用该功能为公众账号的会话界面底部增加自定义菜单,用户点击菜单中的选项,可以调出相应的回复信息或网页链接。自定义菜单接口将为公众账号的信息展示空间提供更多可能性。本文将针对自定义菜单做简单的开发应用,以供读者参考。
  4.  
  5. 二、官方说明
  6.  
  7. 开发者获取使用凭证后,可以使用该凭证对公众账号的自定义菜单进行创建、查询和删除等操作。 自定义菜单接口可实现以下类型按钮:
  8.  
  9. click(点击事件):
  10.  
  11. 用户点击click类型按钮后,微信服务器会通过消息接口(event类型)推送点击事件给开发者,并且带上按钮中开发者填写的key值,开发者可以通过自定义的key值进行消息回复。
  12.  
  13. view(访问网页):
  14.  
  15. 用户点击view类型按钮后,会直接跳转到开发者指定的url中。
  16.  
  17. 创建自定义菜单后,由于微信客户端缓存,需要24小时微信客户端才会展现出来。建议测试时可以尝试取消关注公众账号后,再次关注,则可以看到创建后的效果。
  18.  
  19. 文档地址:http://mp.weixin.qq.com/wiki
  20.  
  21. 三、获取使用凭证
  22.  
  23. 3.1 获取appid appsecret
  24.  
  25. 微信公众平台 > 高级功能 > 开发模式中找到appid appsecret
  26.  
  27. 3.2 使用appid appsecret 向微信凭证获取接口请求access_token
  28.  
  29. 请求地址:https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
  30.  
  31. 请求参数说明:
  32.  
  33. grant_type:获取access_token填写client_credential
  34.  
  35. appid:第三方用户唯一凭证
  36.  
  37. secret:第三方用户唯一凭证密钥,既appsecret
  38.  
  39. 返回说明:
  40.  
  41. 正确的Json返回结果:
  42.  
  43. {"access_token":"ACCESS_TOKEN","expires_in":}
  44.  
  45. 返回参数说明:
  46.  
  47. access_token:获取到的凭证
  48.  
  49. expires_in:凭证有效时间,单位:秒
  50.  

3.3具体实现

  1. //与微信平台那边填写的token一致
    string Token = "tokenAccountName";
    // 获取access_token的接口地址GET方式
  2. public static string access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
  3. public static string createurl = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
  1. public static void CreateMenue(string appid, string appsecret)
  2. {
  3. //获取access_token值
  4. string requestUrl = access_token_url.Replace("APPID", appid).Replace("APPSECRET", appsecret);
  5. WebResponse result = null;
  6. WebRequest req = WebRequest.Create(requestUrl);
  7. result = req.GetResponse();
  8. Stream s = result.GetResponseStream();
  9. XmlDictionaryReader xmlReader = JsonReaderWriterFactory.CreateJsonReader(s, XmlDictionaryReaderQuotas.Max);
  10. xmlReader.Read();
  11. String XMLString = xmlReader.ReadOuterXml();
  12. s.Close();
  13. s.Dispose();
  14. XmlDocument doc = new XmlDocument();
  15. doc.LoadXml(XMLString);
  16. XmlElement rootElement = doc.DocumentElement;
  17. string access_token = rootElement.SelectSingleNode("access_token").InnerText;
  18. //根据access_token值
  19. createurl = createurl.Replace("ACCESS_TOKEN", access_token);
  20. string responeJsonStr = "{" +
  21. "\"button\":[" +
  22. "{\"name\":\"中秋系列\"," +
  23. "\"type\":\"click\"," +
  24. "\"key\":\"V1001_ZhongQiu\"" +
  25. "}" +
  26. ",{\"name\":\"摘星星\"," +
  27. "\"type\":\"click\"," +
  28. "\"key\":\"V1002_ZhaiXing\"" +
  29. "}" +
  30. "]" +
  31. "}";
  32. WebRequest req = WebRequest.Create(createurl);
  33. byte[] bytes = Encoding.UTF8.GetBytes(responeJsonStr.ToString());
  34. req.Method = "POST";
  35. req.ContentType = "application/x-www-form-urlencoded";
  36. req.ContentLength = bytes.Length;
  37. Stream reqStr = req.GetRequestStream();
  38. reqStr.Write(bytes, 0, bytes.Length);
  39. reqSrt.Close();
  40. }
  1. protected void Page_Load(object sender, EventArgs e)
  2. {
  3.  CreateMenue("wxddsd8521111fdfs", "r85f5gf222222222sdsdd2dsdsdsddddd");
  4. string postStr = "";
  5. if (Request.HttpMethod.ToLower() == "POST")
  6. {
  7. Stream s = System.Web.HttpContext.Current.Request.InputStream;
  8. byte[] b = new byte[s.Length];
  9. s.Read(b, , (int)s.Length);
  10. postStr = Encoding.UTF8.GetString(b);
  11. if (!string.IsNullOrEmpty(postStr))
  12. {
  13. XmlDocument doc = new XmlDocument();
  14. doc.LoadXml(postStr);
  15. XmlElement rootElement = doc.DocumentElement;
  16. XmlNode MsgType = rootElement.SelectSingleNode("MsgType");
  17. WeiXinRequest requestXML = new WeiXinRequest();
  18. requestXML.ToUserName = rootElement.SelectSingleNode("ToUserName").InnerText;
  19. requestXML.FromUserName = rootElement.SelectSingleNode("FromUserName").InnerText;
  20. requestXML.CreateTime = rootElement.SelectSingleNode("CreateTime").InnerText;
  21. requestXML.MsgType = MsgType.InnerText;
  22.  
  23. if (requestXML.MsgType == "text")
  24. {
  25. requestXML.Content = rootElement.SelectSingleNode("Content").InnerText;
  26. requestXML.MsgId = rootElement.SelectSingleNode("MsgId").InnerText;
  27. }
  28. else if (requestXML.MsgType == "location")
  29. {
  30. requestXML.Location_X = rootElement.SelectSingleNode("Location_X").InnerText;
  31. requestXML.Location_Y = rootElement.SelectSingleNode("Location_Y").InnerText;
  32.  
  33. }
  34. else if (requestXML.MsgType == "event")
  35. {
  36. requestXML.Wxevent = rootElement.SelectSingleNode("Event").InnerText;
  37. requestXML.EventKey = rootElement.SelectSingleNode("EventKey").InnerText;
  38. }
  39. WriteTxt("---消息,消息类型:" + requestXML.MsgType + "----:" + postStr);
  40. //回复消息
  41. ResponseMsg(requestXML);
  42. }
  43. }
  44. else
  45. {
  46. CheckSource();
  47. }
  48. }
  49. private void CheckSource()
  50. {
  51. string echoStr = Request.QueryString["echoStr"];
  52. if (CheckSignature())
  53. {
  54. if (!string.IsNullOrEmpty(echoStr))
  55. {
  56. Response.Write(echoStr);
  57. Response.End();
  58. }
  59. }
  60. }
  1. private bool CheckSignature()
  2. {
  3. string signature = Request.QueryString["signature"];
  4. string timestamp = Request.QueryString["timestamp"];
  5. string nonce = Request.QueryString["nonce"];
  6. string[] ArrTmp = { Token, timestamp, nonce };
  7. Array.Sort(ArrTmp);
  8. string tmpStr = string.Join("", ArrTmp);
  9. tmpStr = FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1");
  10. tmpStr = tmpStr.ToLower();
  11. if (tmpStr == signature)
  12. {
  13. return true;
  14. }
  15. else
  16. {
  17. return false;
  18. }
  19. }
    private int ConvertDate(System.DateTime time)
            {
                System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
                return (int)(time - startTime).TotalSeconds;
            }
  1. private void ResponseMsg(WeiXinRequest requestXML)
    {
    string resxml = "<xml><ToUserName><![CDATA[" + requestXML.FromUserName + "]]></ToUserName><FromUserName><![CDATA[" + requestXML.ToUserName + "]]></FromUserName><CreateTime>" + ConvertDate(DateTime.Now) + "</CreateTime>";
    try
    {
    if (requestXML.MsgType == "text")
    {
    int count = ;
    resxml += "<MsgType><![CDATA[text]]></MsgType><Content><![CDATA[好看信息]]></Content><FuncFlag>0</FuncFlag></xml>"; //}
    }
    else if (requestXML.MsgType == "location")
    {
    resxml += "<MsgType><![CDATA[text]]></MsgType><Content><![CDATA[坐标消息]]></Content><FuncFlag>0</FuncFlag></xml>";
    }
  1. else if (requestXML.MsgType == "event")
  2. {
  3. if (requestXML.Wxevent == "unsubscribe")
  4. {
  5. //取消关注
  6. }
  7. else if (requestXML.Wxevent == "subscribe")
  8. {
  9. //新增关注
  10. resxml += "<MsgType><![CDATA[text]]></MsgType><Content><![CDATA[感谢关注!]]></Content><FuncFlag>0</FuncFlag></xml>";
  11. }
  12. else if (requestXML.Wxevent.ToUpper() == "CLICK")
  13. {
  14. if (requestXML.EventKey == "V1001_ZhongQiu") { string P_Code = ""; }
    else if (requestXML.EventKey == "V1002_ZhaiXing") { resxml += "<MsgType><![CDATA[news]]></MsgType><ArticleCount>" + + "</ArticleCount><Articles>";
    resxml += "<item><Title><![CDATA[摘颗星星给你]]></Title><Description><![CDATA[查看您的中秋惊喜]]></Description><Url><![CDATA[" + Request.Url.Authority + "/WeiXin/PurchaseLogin.aspx?weixinId=" + requestXML.FromUserName + "&gzhID=" + requestXML.ToUserName + "]]></Url></item>"; resxml += "</Articles><FuncFlag>0</FuncFlag></xml>"; } } } }
    catch (Exception ex) { WriteTxt("异常:" + ex.Message); }
    WriteTxt("返回给对方的消息:" + resxml);
    Response.Write(resxml); Response.End(); }
     public bool WriteTxt(string str)
            {
                try
                {
                    FileStream fs = new FileStream(Server.MapPath("/Log.txt"), FileMode.Append);
                    StreamWriter sw = new StreamWriter(fs);
                    sw.WriteLine(str);
                    sw.Flush();
                    sw.Close();
                    fs.Close();
                }
                catch (Exception)
                {
                    return false;
                }
                return true;
            }
        }
    }
  15.  
  16. public class WeiXinRequest
  17. {
  18. private string toUserName;
  19. /// <summary>
  20. /// 消息接收方微信号
  21. /// </summary>
  22. public string ToUserName
  23. {
  24. get { return toUserName; }
  25. set { toUserName = value; }
  26. }
  27.  
  28. private string fromUserName;
  29. /// <summary>
  30. /// 消息发送方微信号
  31. /// </summary>
  32. public string FromUserName
  33. {
  34. get { return fromUserName; }
  35. set { fromUserName = value; }
  36. }
  37.  
  38. private string createTime;
  39. /// <summary>
  40. /// 创建时间
  41. /// </summary>
  42. public string CreateTime
  43. {
  44. get { return createTime; }
  45. set { createTime = value; }
  46. }
  47. private string msgType;
  48. /// <summary>
  49. /// 信息类型 文本消息:text,消息类型:image,音频:voice,视频:video,
  50. /// </summary>
  51. public string MsgType
  52. {
  53. get { return msgType; }
  54. set { msgType = value; }
  55. }
  56.  
  57. private string content;
  58. /// <summary>
  59. /// 信息内容
  60. /// </summary>
  61. public string Content
  62. {
  63. get { return content; }
  64. set { content = value; }
  65. }
  66. private string msgId;
  67. /// <summary>
  68. /// 消息ID(文本)
  69. /// </summary>
  70. public string MsgId
  71. {
  72. get { return msgId; }
  73. set { msgId = value; }
  74. }
  75.  
  76. private string wxevent;
  77. /// <summary>
  78. /// 取消关注时的Event节点
  79. /// </summary>
  80. public string Wxevent
  81. {
  82. get { return wxevent; }
  83. set { wxevent = value; }
  84. }
  85.  
  86. private string eventKey;
  87. /// <summary>
  88. /// 取消关注时的EventKey节点
  89. /// </summary>
  90. public string EventKey
  91. {
  92. get { return eventKey; }
  93. set { eventKey = value; }
  94. }
  95.  
  96. private string location_X;
  97. /// <summary>
  98. /// 坐标维度
  99. /// </summary>
  100. public string Location_X
  101. {
  102. get { return location_X; }
  103. set { location_X = value; }
  104. }
  105.  
  106. private string location_Y;
  107. /// <summary>
  108. /// 经度
  109. /// </summary>
  110. public string Location_Y
  111. {
  112. get { return location_Y; }
  113. set { location_Y = value; }
  114. }
  115.  
  116. private string picUrl;
  117. /// <summary>
  118. /// 图片链接
  119. /// </summary>
  120. public string PicUrl
  121. {
  122. get { return picUrl; }
  123. set { picUrl = value; }
  124. }
  125. }
  1.  
  1.  

.NET开发微信公众号之创建自定义菜单的更多相关文章

  1. tp6微信公众号开发者模式自定义菜单

    1,参考上篇博客,获取access_token https://www.cnblogs.com/xiaoyantongxue/p/15803334.html 2:控制器写以下代码 /* * 获取普通a ...

  2. 微信公众号开发者模式自定义菜单 node

    纯属分享 var config = require('./admin/wx/config/config'); var API = require('wechat-api'); var api = ne ...

  3. Java开发微信公众号(五)---微信开发中如何获取access_token以及缓存access_token

    获取access_token是微信api最重要的一个部分,因为调用其他api很多都需要用到access_token.比如自定义菜单接口.客服接口.获取用户信息接口.用户分组接口.群发接口等在请求的时候 ...

  4. Java开发微信公众号(三)---微信服务器请求消息,响应消息,事件消息以及工具处理类的封装

    在前面几篇文章我们讲了微信公众号环境的配置 和微信公众号服务的接入,接下来我们来说一下微信服务器请求消息,响应消息以及事件消息的相关内容,首先我们来分析一下消息类型和返回xml格式及实体类的封装. ( ...

  5. vue开发微信公众号--开发准备

    由于工作项目的原因,需要使用vue开发微信公众号,但是这种微信公众号更多是将APP套了一个微信的壳子,除了前面的授权和微信有关系以外,其他的都和微信没多大的关系了,特此记录 开发流程 首先需要在电脑上 ...

  6. php开发微信公众号获取信息LBS

    1.一般的公众号都可以在微信公众平台里面设置自定义菜单和自动回复消息,如果需要获取用户位置,则必须开启 服务器配置,当次功能开启后,微信公众平台的自定义菜单和自动回复则失效. 需要通过接口开发来实现微 ...

  7. Java开发微信公众号(四)---微信服务器post消息体的接收及消息的处理

    在前几节文章中我们讲述了微信公众号环境的搭建.如何接入微信公众平台.以及微信服务器请求消息,响应消息,事件消息以及工具处理类的封装:接下来我们重点说一下-微信服务器post消息体的接收及消息的处理,这 ...

  8. Java开发微信公众号(二)---开启开发者模式,接入微信公众平台开发

    接入微信公众平台开发,开发者需要按照如下步骤完成: 1.填写服务器配置 2.验证服务器地址的有效性 3.依据接口文档实现业务逻辑 资料准备: 1.一个可以访问的外网,即80的访问端口,因为微信公众号接 ...

  9. Java开发微信公众号(一)---初识微信公众号以及环境搭建

    ps:1.开发语言使用Java springMvc+Mybaits+spring maven实现 2.使用微信接口测试账号进行本地测试 https://mp.weixin.qq.com/debug/c ...

随机推荐

  1. Python库资源大全

    转载地址:https://zhuanlan.zhihu.com/p/27350980 本文是一个精心设计的Python框架.库.软件和资源列表,是一个Awesome XXX系列的资源整理,由BigQu ...

  2. Cube Stack

    Cube Stack 有一点lazy思想,设三个数组cnt代表它以下的有多少个元素(直到栈底),top[x]代表x所在栈的栈顶元素,dad[x]代表x所在栈的栈底元素,先寻找父亲,然后递归更新累加cn ...

  3. vue-particles粒子动画效果

    1.安装vue-particles依赖包 npm install vue-particles --save-dev 2.在main.js文件中引入并使用 import Vue from 'vue' i ...

  4. saxon 处理xslt

    下载saxon : https://sourceforge.net/projects/saxon/?source=typ_redirect 下载后拿到: saxon9he.jar 运行CMD: C:\ ...

  5. Bootstrap 警告、进度条、列表组、面板

    摘要:该部分包括警告.进度条.列表组.面板等部分. 1.警告(alert) 1.1 基本的警告(.alert) 警告的基类是 .alert .和其他样式类一块使用.例如: .alert-success ...

  6. redis清除缓存和连接远程服务器

    直接进入命令行输入 1.连接远程redis:   redis-cli -h 127.0.0.1 -p 3008 -a pIctur3   (a后是密码) 2.查看缓存:keys * 3.清除缓存:de ...

  7. Minor GC 与Full GC有什么不一样

    新生代GC(Minor GC):指发生在新生代的垃圾收集动作,因为java对象大多都具备朝生夕灭的特性,所以Minor GC非常频繁,一般回收速度也非常快 老年代GC(Major GC/Full GC ...

  8. 第一章 flex单词计数程序

    学习Flex&Bison目标, 读懂SQLite中SQL解析部分代码 Flex&Bison简介Flex做词法分析Bison做语法分析 第一个Flex程序, wc.fl, 单词计数程序 ...

  9. Using a Virtex Device to Drive 5V CMOS-Level Signals

    Must tri-state outputs and use an external resistor to pull up to 5V To drive 5V CMOS-level inputs, ...

  10. 手机号是SIM卡的号呢,还是买手机时就带的

    可以用原来的号码!把原来的卡装在新手机里就可以了,你的号码没有改变! 手机的号是由sim卡来决定的! 但是卡上的号码显示的是卡的一些信息! 你不用去理会它! 全文:http://iask.sina.c ...