.NET开发微信公众号之创建自定义菜单

时间:2023-02-20 22:22:31
一、简介

微信公众平台服务号以及之前成功申请内测资格的订阅号都具有自定义菜单的功能。开发者可利用该功能为公众账号的会话界面底部增加自定义菜单,用户点击菜单中的选项,可以调出相应的回复信息或网页链接。自定义菜单接口将为公众账号的信息展示空间提供更多可能性。本文将针对自定义菜单做简单的开发应用,以供读者参考。

二、官方说明

开发者获取使用凭证后,可以使用该凭证对公众账号的自定义菜单进行创建、查询和删除等操作。 自定义菜单接口可实现以下类型按钮:

click(点击事件):

用户点击click类型按钮后,微信服务器会通过消息接口(event类型)推送点击事件给开发者,并且带上按钮中开发者填写的key值,开发者可以通过自定义的key值进行消息回复。

view(访问网页):

用户点击view类型按钮后,会直接跳转到开发者指定的url中。

创建自定义菜单后,由于微信客户端缓存,需要24小时微信客户端才会展现出来。建议测试时可以尝试取消关注公众账号后,再次关注,则可以看到创建后的效果。

文档地址:http://mp.weixin.qq.com/wiki

三、获取使用凭证

3.1 获取appid 和appsecret

在 微信公众平台 > 高级功能 > 开发模式中找到appid 和appsecret。

3.2 使用appid 和appsecret 向微信凭证获取接口请求access_token

请求地址:https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

请求参数说明:

grant_type:获取access_token填写client_credential

appid:第三方用户唯一凭证

secret:第三方用户唯一凭证密钥,既appsecret

返回说明:

正确的Json返回结果:

{"access_token":"ACCESS_TOKEN","expires_in":}

返回参数说明:

access_token:获取到的凭证

expires_in:凭证有效时间,单位:秒

3.3具体实现

      //与微信平台那边填写的token一致
string Token = "tokenAccountName";
// 获取access_token的接口地址GET方式
public static string access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
public static string createurl = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
 public static void CreateMenue(string appid, string appsecret)
{
//获取access_token值
string requestUrl = access_token_url.Replace("APPID", appid).Replace("APPSECRET", appsecret);
WebResponse result = null;
WebRequest req = WebRequest.Create(requestUrl);
result = req.GetResponse();
Stream s = result.GetResponseStream();
XmlDictionaryReader xmlReader = JsonReaderWriterFactory.CreateJsonReader(s, XmlDictionaryReaderQuotas.Max);
xmlReader.Read();
String XMLString = xmlReader.ReadOuterXml();
s.Close();
s.Dispose();
XmlDocument doc = new XmlDocument();
doc.LoadXml(XMLString);
XmlElement rootElement = doc.DocumentElement;
string access_token = rootElement.SelectSingleNode("access_token").InnerText;
//根据access_token值
createurl = createurl.Replace("ACCESS_TOKEN", access_token);
string responeJsonStr = "{" +
"\"button\":[" +
"{\"name\":\"中秋系列\"," +
"\"type\":\"click\"," +
"\"key\":\"V1001_ZhongQiu\"" +
"}" +
",{\"name\":\"摘星星\"," +
"\"type\":\"click\"," +
"\"key\":\"V1002_ZhaiXing\"" +
"}" +
"]" +
"}";
WebRequest req = WebRequest.Create(createurl);
byte[] bytes = Encoding.UTF8.GetBytes(responeJsonStr.ToString());
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bytes.Length;
Stream reqStr = req.GetRequestStream();
reqStr.Write(bytes, 0, bytes.Length);
reqSrt.Close();
}
protected void Page_Load(object sender, EventArgs e)
{
 CreateMenue("wxddsd8521111fdfs", "r85f5gf222222222sdsdd2dsdsdsddddd");
string postStr = "";
if (Request.HttpMethod.ToLower() == "POST")
{
Stream s = System.Web.HttpContext.Current.Request.InputStream;
byte[] b = new byte[s.Length];
s.Read(b, , (int)s.Length);
postStr = Encoding.UTF8.GetString(b);
if (!string.IsNullOrEmpty(postStr))
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(postStr);
XmlElement rootElement = doc.DocumentElement;
XmlNode MsgType = rootElement.SelectSingleNode("MsgType");
WeiXinRequest requestXML = new WeiXinRequest();
requestXML.ToUserName = rootElement.SelectSingleNode("ToUserName").InnerText;
requestXML.FromUserName = rootElement.SelectSingleNode("FromUserName").InnerText;
requestXML.CreateTime = rootElement.SelectSingleNode("CreateTime").InnerText;
requestXML.MsgType = MsgType.InnerText; if (requestXML.MsgType == "text")
{
requestXML.Content = rootElement.SelectSingleNode("Content").InnerText;
requestXML.MsgId = rootElement.SelectSingleNode("MsgId").InnerText;
}
else if (requestXML.MsgType == "location")
{
requestXML.Location_X = rootElement.SelectSingleNode("Location_X").InnerText;
requestXML.Location_Y = rootElement.SelectSingleNode("Location_Y").InnerText; }
else if (requestXML.MsgType == "event")
{
requestXML.Wxevent = rootElement.SelectSingleNode("Event").InnerText;
requestXML.EventKey = rootElement.SelectSingleNode("EventKey").InnerText;
}
WriteTxt("---消息,消息类型:" + requestXML.MsgType + "----:" + postStr);
//回复消息
ResponseMsg(requestXML);
}
}
else
{
CheckSource();
}
}
private void CheckSource()
{
string echoStr = Request.QueryString["echoStr"];
if (CheckSignature())
{
if (!string.IsNullOrEmpty(echoStr))
{
Response.Write(echoStr);
Response.End();
}
}
}
 private bool CheckSignature()
{
string signature = Request.QueryString["signature"];
string timestamp = Request.QueryString["timestamp"];
string nonce = Request.QueryString["nonce"];
string[] ArrTmp = { Token, timestamp, nonce };
Array.Sort(ArrTmp);
string tmpStr = string.Join("", ArrTmp);
tmpStr = FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1");
tmpStr = tmpStr.ToLower();
if (tmpStr == signature)
{
return true;
}
else
{
return false;
}
}
private int ConvertDate(System.DateTime time)
        {
            System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
            return (int)(time - startTime).TotalSeconds;
        }
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>";
}
else if (requestXML.MsgType == "event")
{
if (requestXML.Wxevent == "unsubscribe")
{
//取消关注
}
else if (requestXML.Wxevent == "subscribe")
{
//新增关注
resxml += "<MsgType><![CDATA[text]]></MsgType><Content><![CDATA[感谢关注!]]></Content><FuncFlag>0</FuncFlag></xml>";
}
else if (requestXML.Wxevent.ToUpper() == "CLICK")
{
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;
        }
    }
} public class WeiXinRequest
{
private string toUserName;
/// <summary>
/// 消息接收方微信号
/// </summary>
public string ToUserName
{
get { return toUserName; }
set { toUserName = value; }
} private string fromUserName;
/// <summary>
/// 消息发送方微信号
/// </summary>
public string FromUserName
{
get { return fromUserName; }
set { fromUserName = value; }
} private string createTime;
/// <summary>
/// 创建时间
/// </summary>
public string CreateTime
{
get { return createTime; }
set { createTime = value; }
}
private string msgType;
/// <summary>
/// 信息类型 文本消息:text,消息类型:image,音频:voice,视频:video,
/// </summary>
public string MsgType
{
get { return msgType; }
set { msgType = value; }
} private string content;
/// <summary>
/// 信息内容
/// </summary>
public string Content
{
get { return content; }
set { content = value; }
}
private string msgId;
/// <summary>
/// 消息ID(文本)
/// </summary>
public string MsgId
{
get { return msgId; }
set { msgId = value; }
} private string wxevent;
/// <summary>
/// 取消关注时的Event节点
/// </summary>
public string Wxevent
{
get { return wxevent; }
set { wxevent = value; }
} private string eventKey;
/// <summary>
/// 取消关注时的EventKey节点
/// </summary>
public string EventKey
{
get { return eventKey; }
set { eventKey = value; }
} private string location_X;
/// <summary>
/// 坐标维度
/// </summary>
public string Location_X
{
get { return location_X; }
set { location_X = value; }
} private string location_Y;
/// <summary>
/// 经度
/// </summary>
public string Location_Y
{
get { return location_Y; }
set { location_Y = value; }
} private string picUrl;
/// <summary>
/// 图片链接
/// </summary>
public string PicUrl
{
get { return picUrl; }
set { picUrl = value; }
}
}

 

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

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

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

  2. Java开发微信公众号(五)---微信开发中如何获取access&lowbar;token以及缓存access&lowbar;token

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

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

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

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

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

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

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

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

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

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

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

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

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

  9. Spring Boot 开发微信公众号后台

    Hello 各位小伙伴,松哥今天要和大家聊一个有意思的话题,就是使用 Spring Boot 开发微信公众号后台. 很多小伙伴可能注意到松哥的个人网站(http://www.javaboy.org)前 ...

随机推荐

  1. 简单的css js控制table隔行变色

    (1)用expression 鼠标滑过变色: <style type="text/css"><!-- table { background-color:#0000 ...

  2. jQ HTML之捕获 设置 元素添加与删除

    捕获 设置修改 添加元素 删除元素

  3. C&num;的 构造函数 和 方法重载

    构造函数(一本正经的讲构造函数 如果想看不正经的往下翻看方法重载) 方法名称与类名相同,没有返回值类型,连void都没有 用作给类的对象初始化 一个类中可以有多个构造 如果手动添加一个构造,系统不会自 ...

  4. DOS命令符基本操作

    怎么改变DOS默认路径 开始->所有程序->附件->命令提示符,在“命令提示符”上右键,选择“属性”,(或者在快捷方式上点击属性)会弹出一个“命令提示符 属性”对话框,可以通过修改该 ...

  5. WebApi实现跨域功能

    在配置文件的system.webServer节点中加入以下配置信息 <httpProtocol> <customHeaders> <add name="Acce ...

  6. express实践&lpar;一&rpar;

    涉及以下这些内容: 主体. cookie.session 数据 模板引擎 服务器基本结构: const express=require('express'); const static=require ...

  7. nativefier - 快速把任意网页生成桌面应用程序

    使用前端技术开发桌面应用的技术已经相当成熟了,像早先的 NW.js,如今很火的 Electron 等,都可以轻松实现.今天给大家分享的 nativefier 就是基于 Electron 封装的,可以帮 ...

  8. DOM的查找,新增,删除操作

    查找 1. document.getElementById()  通过ID获取元素,由于ID唯一,所以获取的是一个元素 2. document.getElementsByTagName() 通过标签名 ...

  9. DevOps之持续交付

    持续交付 持续交付是一种可以帮助团队以更短的周期交付软件的方法,该方法确保了团队可以在任何时间发布出可靠的软件.该方法意在以更快速度更高频率进行软件的构建.测试和发布. 通过对生产环境中的应用程序进行 ...

  10. Linux学习之常用系统工作命令&lpar;一&rpar;

     由于centos和RHEL互通,两个版本可以相互学习,所以截图有两个界面 Linux系统与win系列是两个几乎完全不同的操作系统,但是就应用范围来说,是win系统更胜一筹,然而,这反而也成为win系 ...