.NET开发微信公众号之创建自定义菜单
一、简介
微信公众平台服务号以及之前成功申请内测资格的订阅号都具有自定义菜单的功能。开发者可利用该功能为公众账号的会话界面底部增加自定义菜单,用户点击菜单中的选项,可以调出相应的回复信息或网页链接。自定义菜单接口将为公众账号的信息展示空间提供更多可能性。本文将针对自定义菜单做简单的开发应用,以供读者参考。
二、官方说明
开发者获取使用凭证后,可以使用该凭证对公众账号的自定义菜单进行创建、查询和删除等操作。 自定义菜单接口可实现以下类型按钮:
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开发微信公众号之创建自定义菜单的更多相关文章
- tp6微信公众号开发者模式自定义菜单
1,参考上篇博客,获取access_token https://www.cnblogs.com/xiaoyantongxue/p/15803334.html 2:控制器写以下代码 /* * 获取普通a ...
- 微信公众号开发者模式自定义菜单 node
纯属分享 var config = require('./admin/wx/config/config'); var API = require('wechat-api'); var api = ne ...
- Java开发微信公众号(五)---微信开发中如何获取access_token以及缓存access_token
获取access_token是微信api最重要的一个部分,因为调用其他api很多都需要用到access_token.比如自定义菜单接口.客服接口.获取用户信息接口.用户分组接口.群发接口等在请求的时候 ...
- Java开发微信公众号(三)---微信服务器请求消息,响应消息,事件消息以及工具处理类的封装
在前面几篇文章我们讲了微信公众号环境的配置 和微信公众号服务的接入,接下来我们来说一下微信服务器请求消息,响应消息以及事件消息的相关内容,首先我们来分析一下消息类型和返回xml格式及实体类的封装. ( ...
- vue开发微信公众号--开发准备
由于工作项目的原因,需要使用vue开发微信公众号,但是这种微信公众号更多是将APP套了一个微信的壳子,除了前面的授权和微信有关系以外,其他的都和微信没多大的关系了,特此记录 开发流程 首先需要在电脑上 ...
- php开发微信公众号获取信息LBS
1.一般的公众号都可以在微信公众平台里面设置自定义菜单和自动回复消息,如果需要获取用户位置,则必须开启 服务器配置,当次功能开启后,微信公众平台的自定义菜单和自动回复则失效. 需要通过接口开发来实现微 ...
- Java开发微信公众号(四)---微信服务器post消息体的接收及消息的处理
在前几节文章中我们讲述了微信公众号环境的搭建.如何接入微信公众平台.以及微信服务器请求消息,响应消息,事件消息以及工具处理类的封装:接下来我们重点说一下-微信服务器post消息体的接收及消息的处理,这 ...
- Java开发微信公众号(二)---开启开发者模式,接入微信公众平台开发
接入微信公众平台开发,开发者需要按照如下步骤完成: 1.填写服务器配置 2.验证服务器地址的有效性 3.依据接口文档实现业务逻辑 资料准备: 1.一个可以访问的外网,即80的访问端口,因为微信公众号接 ...
- Java开发微信公众号(一)---初识微信公众号以及环境搭建
ps:1.开发语言使用Java springMvc+Mybaits+spring maven实现 2.使用微信接口测试账号进行本地测试 https://mp.weixin.qq.com/debug/c ...
随机推荐
- 001.Docker简介概述
一 简介 Docker最初是dotCloud公司的一个内部项目,诞生于 2013 年初,由google公司开源的Go语言开发. Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的.可移 ...
- spring aop简单理解
aop原理是spring帮我们封装了动态代理,然后我们只管写具体的业务,我们将公共业务也写到具体的一个类中并实现spring为我们提供的对应要连接切入哪个位置的接口,然后再xml中配置它们的关系即可. ...
- 虚拟机克隆后导致两台机器的IP都不显示的解决方法
centos7中输入ifconfig出现ens33,没有eth0,也没有ip,不能上网,输入ifconfig后如下图 之前在网上也找了很多的方法,比如删除文件70-persistent-ipoib.r ...
- 观察者模式之ES6实现(二)
一.问题描述实现一个EventEmitter类,这个类包含以下方法:on(监听事件,该事件可以被触发多次)once(也是监听事件,但只能被触发一次)fire(触发指定的事件)off(移除指定事件的某个 ...
- 利用django信号实现计数功能
本文主要知识点: 1.使用Django的signals来获取Model的新建/删除操作更新 2.使用数据库的select for update来正确处理并发的数据库操作 3.使用redis的sorte ...
- android studio git 将项目分享到github,推送到其他平台 码云 等。
android studio git 将项目分享到github,推送到其他平台 码云 等. 作者:韩梦飞沙 Author:han_meng_fei_sha 邮箱:313134555@qq.com E- ...
- Codeforces.1051F.The Shortest Statement(最短路Dijkstra)
题目链接 先随便建一棵树. 如果两个点(u,v)不经过非树边,它们的dis可以直接算. 如果两个点经过非树边呢?即它们一定要经过该边的两个端点,可以直接用这两个点到 u,v 的最短路更新答案. 所以枚 ...
- NOIP 2000 乘积最大
分析: 这一题虽然是加强版的,但也就是数据范围比原题大了点儿,思路都一样,在原题的基础上加一个高精度乘法就OK了,下面说一下算法:看到题首先想到的就是动态规划,你会发现这一题极像一道经典题目---添加 ...
- 命令行方式删除文件 && 文件夹
del File: 删除文件 rmdir Folder : 删除文件夹 [貌似只能删除空目录] rm -rf Folder: 删除非空文件夹 [用windows自带的cmd提示我“rm”不是内部命令 ...
- MAC自动脚本
链接: crontab 详细用法 定时任务 Linux crontab命令 定时任务 用法详解以及no crontab for root解决办法