CustomMenuAPI.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /*--------------------------------------------------------------------------
  2. * CustomMenu.cs
  3. *Auth:deepleo
  4. * Date:2013.12.31
  5. * Email:2586662969@qq.com
  6. * Website:http://www.weixinsdk.net
  7. *--------------------------------------------------------------------------*/
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Linq;
  11. using System.Text;
  12. using System.Net.Http;
  13. using Codeplex.Data;
  14. using System.Xml;
  15. namespace LYFZ.Weixin.SDK
  16. {
  17. /// <summary>
  18. /// "自定义菜单”
  19. /// http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E5%88%9B%E5%BB%BA%E6%8E%A5%E5%8F%A3
  20. /// 注意:自定义菜单事件推送接口见:AcceptMessageAPI
  21. /// 创建自定义菜单后,由于微信客户端缓存,需要24小时微信客户端才会展现出来,测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的效果。
  22. /// 自定义菜单种类如下:
  23. /// 1、click:点击推事件
  24. /// 2、view:跳转URL
  25. /// 3、scancode_push:扫码推事件
  26. /// 4、scancode_waitmsg:扫码推事件且弹出“消息接收中”提示框
  27. /// 5、pic_sysphoto:弹出系统拍照发图
  28. /// 6、pic_photo_or_album:弹出拍照或者相册发图
  29. /// 7、pic_weixin:弹出微信相册发图器
  30. /// 8、location_select:弹出地理位置选择器
  31. /// </summary>
  32. public class CustomMenuAPI
  33. {
  34. public static T parse<T>(string jsonString)
  35. {
  36. using (var ms = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(jsonString)))
  37. {
  38. return (T)new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(T)).ReadObject(ms);
  39. }
  40. }
  41. /// <summary>
  42. /// 获取要创建的菜单数据字符串
  43. /// </summary>
  44. /// <param name="menu_buttons"></param>
  45. /// <returns></returns>
  46. public static string GetMenuDataString(List<MenuModel> menu_buttons)
  47. {
  48. string menuModelString = "";
  49. for (int i = 0; i < 3; i++)
  50. {
  51. if (i < menu_buttons.Count)
  52. {
  53. MenuModel button = menu_buttons[i];
  54. menuModelString += button.ToString() + ",";
  55. }
  56. else
  57. {
  58. break;
  59. }
  60. }
  61. string dataString = "{\"button\":[" + menuModelString.Trim(',') + "]}";
  62. return dataString;
  63. }
  64. /// <summary>
  65. /// 获取要创建的菜单数据XML
  66. /// </summary>
  67. /// <param name="menu_buttons"></param>
  68. /// <returns></returns>
  69. public static string GetMenuDataXML(List<MenuModel> menu_buttons)
  70. {
  71. string menuModelString = "";
  72. if (menu_buttons.Count > 0)
  73. {
  74. for (int i = 0; i < 3; i++)
  75. {
  76. if (i < menu_buttons.Count)
  77. {
  78. MenuModel button = menu_buttons[i];
  79. menuModelString += button.ToXml();
  80. }
  81. else
  82. {
  83. break;
  84. }
  85. }
  86. return "<menu>" + menuModelString + "</menu>";
  87. }
  88. return "";
  89. }
  90. /// <summary>
  91. /// 测试用
  92. /// </summary>
  93. /// <returns></returns>
  94. public static string GetTempXmlString()
  95. {
  96. return "<menu>"
  97. +" <button> "
  98. +" <name>工具箱</name> "
  99. +" <sub_button> "
  100. +" <type>view</type> "
  101. +" <name>百度搜索</name> "
  102. +" <url>http://www.baidu.com/</url> "
  103. +" </sub_button> "
  104. +" <sub_button> "
  105. +" <type>view</type> "
  106. +" <name>QQ视频</name> "
  107. +" <url>http://v.qq.com/</url> "
  108. +" </sub_button> "
  109. +" <sub_button> "
  110. +" <type>view</type> "
  111. +" <name>手机APP</name> "
  112. +" <url>http://yifox.oicp.net/WebMobile/Main.aspx/</url> "
  113. +" </sub_button> "
  114. +" <sub_button> "
  115. +" <type>scancode_waitmsg</type> "
  116. +" <name>扫码带提示</name> "
  117. +" <key>rselfmenu_0_0</key> "
  118. +" </sub_button> "
  119. +" <sub_button> "
  120. +" <type>scancode_push</type> "
  121. +" <name>扫码推事件</name> "
  122. +" <key>rselfmenu_0_1</key> "
  123. +" </sub_button> "
  124. +" </button> "
  125. +" <button> "
  126. +" <name>业务查询</name> "
  127. +" <sub_button> "
  128. +" <type>click</type> "
  129. +" <name>订单查询</name> "
  130. +" <key>Order_Query</key> "
  131. +" </sub_button> "
  132. +" "
  133. +" <sub_button> "
  134. +" <type>click</type> "
  135. +" <name>流程查询</name> "
  136. +" <key>Process_Query</key> "
  137. +" </sub_button> "
  138. +" <sub_button> "
  139. +" <type>click</type> "
  140. +" <name>会员查询</name> "
  141. +" <key>Member_Query</key> "
  142. +" </sub_button> "
  143. +" </button> "
  144. +" <button> "
  145. +" <type>click</type> "
  146. +" <name>帮助</name> "
  147. +" <key>BTN_HELP</key> "
  148. +" </button> "
  149. +" </menu>";
  150. }
  151. /// <summary>
  152. /// 获取菜单对象集合
  153. /// </summary>
  154. /// <param name="xml"></param>
  155. /// <returns></returns>
  156. public static List<MenuModel> GetMenuModelList(System.Xml.XmlDocument xml)
  157. {
  158. //xml = new XmlDocument();
  159. // xml.LoadXml(GetTempXmlString());测试用
  160. List<MenuModel> menu_buttons = new List<MenuModel>();
  161. XmlNode xmlNode = xml.SelectSingleNode("menu");
  162. XmlNodeList nodeList = xmlNode.SelectNodes("button");
  163. foreach (XmlNode node in nodeList)
  164. {
  165. MenuModel menu_button = getMenuModel(node);
  166. menu_buttons.Add(menu_button);
  167. }
  168. return menu_buttons;
  169. }
  170. static MenuModel getMenuModel(XmlNode node)
  171. {
  172. MenuModel menu_button = new MenuModel();
  173. try
  174. {
  175. if (node.SelectSingleNode("name") != null)
  176. {
  177. menu_button.Name = node.SelectSingleNode("name").InnerText;
  178. }
  179. if (node.SelectSingleNode("type") != null)
  180. {
  181. menu_button.Type = (WXMenuType)Enum.Parse(typeof(WXMenuType), node.SelectSingleNode("type").InnerText);
  182. }
  183. if (node.SelectSingleNode("key") != null)
  184. {
  185. menu_button.Key = node.SelectSingleNode("key").InnerText;
  186. }
  187. if (node.SelectSingleNode("url") != null)
  188. {
  189. menu_button.Url = System.Web.HttpUtility.UrlDecode(node.SelectSingleNode("url").InnerText.Replace("&amp;","&"));
  190. }
  191. if (node.SelectSingleNode("media_id") != null)
  192. {
  193. menu_button.Media_id = node.SelectSingleNode("media_id").InnerText;
  194. }
  195. XmlNodeList sub_nodeList = node.SelectNodes("sub_button");
  196. if (sub_nodeList != null && sub_nodeList.Count > 0)
  197. {
  198. List<MenuModel> subMenuModelList = new List<MenuModel>();
  199. foreach (XmlNode subNode in sub_nodeList)
  200. {
  201. subMenuModelList.Add(getMenuModel(subNode));
  202. }
  203. menu_button.Sub_buttons = subMenuModelList;
  204. }
  205. }
  206. catch { }
  207. return menu_button;
  208. }
  209. //回调验证证书问题
  210. public static bool CheckValidationResult(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors errors)
  211. {
  212. // 总是接受
  213. return true;
  214. }
  215. public static void SetServicePointManagerSecurityProtocol(string url)
  216. {
  217. System.Net.ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckValidationResult);
  218. if (url.ToLower().StartsWith("https"))
  219. {
  220. System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls;
  221. }
  222. else
  223. {
  224. System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Ssl3;
  225. }
  226. }
  227. /// <summary>
  228. /// 自定义菜单创建接口 直接返回字符串信息
  229. /// </summary>
  230. public static string CreateMenu(string access_token, string content)
  231. {
  232. SetServicePointManagerSecurityProtocol("https:");
  233. var client = new HttpClient();
  234. var result = client.PostAsync(string.Format("https://api.weixin.qq.com/cgi-bin/menu/create?access_token={0}", access_token), new StringContent(content)).Result;
  235. return result.Content.ReadAsStringAsync().Result;
  236. }
  237. /// <summary>
  238. /// 自定义菜单创建接口
  239. /// </summary>
  240. /// <param name="token"></param>
  241. /// <param name="content"></param>
  242. /// <returns></returns>
  243. public static bool Create(string access_token, string content)
  244. {
  245. SetServicePointManagerSecurityProtocol("https:");
  246. var client = new HttpClient();
  247. var result = client.PostAsync(string.Format("https://api.weixin.qq.com/cgi-bin/menu/create?access_token={0}", access_token), new StringContent(content)).Result;
  248. return DynamicJson.Parse(result.Content.ReadAsStringAsync().Result).errcode == 0;
  249. }
  250. /// <summary>
  251. /// 自定义菜单查询接口 直接返回字符串信息
  252. /// </summary>
  253. public static string GetMenu(string access_token)
  254. {
  255. SetServicePointManagerSecurityProtocol("https:");
  256. var client = new HttpClient();
  257. var result = client.GetAsync(string.Format("https://api.weixin.qq.com/cgi-bin/menu/get?access_token={0}", access_token)).Result;
  258. // if (!result.IsSuccessStatusCode) return "自定义菜单查询接口请求失败...";
  259. return result.Content.ReadAsStringAsync().Result;
  260. }
  261. /// <summary>
  262. /// 自定义菜单查询接口
  263. /// </summary>
  264. /// <param name="token"></param>
  265. /// <returns></returns>
  266. public static dynamic Query(string access_token)
  267. {
  268. SetServicePointManagerSecurityProtocol("https:");
  269. var client = new HttpClient();
  270. var result = client.GetAsync(string.Format("https://api.weixin.qq.com/cgi-bin/menu/get?access_token={0}", access_token)).Result;
  271. if (!result.IsSuccessStatusCode) return null;
  272. return DynamicJson.Parse(result.Content.ReadAsStringAsync().Result);
  273. }
  274. /// <summary>
  275. /// 自定义菜单删除接口
  276. /// </summary>
  277. /// <param name="token"></param>
  278. /// <returns></returns>
  279. public static bool Delete(string access_token)
  280. {
  281. SetServicePointManagerSecurityProtocol("https:");
  282. var client = new HttpClient();
  283. var result = client.GetAsync(string.Format("https://api.weixin.qq.com/cgi-bin/menu/delete?access_token={0}", access_token)).Result;
  284. if (!result.IsSuccessStatusCode) return false;
  285. return DynamicJson.Parse(result.Content.ReadAsStringAsync().Result).errmsg == "ok";
  286. }
  287. /// <summary>
  288. /// 自定义菜单删除接口
  289. /// </summary>
  290. /// <param name="token"></param>
  291. /// <returns></returns>
  292. public static string DeleteMenu(string access_token)
  293. {
  294. SetServicePointManagerSecurityProtocol("https:");
  295. var client = new HttpClient();
  296. var result = client.GetAsync(string.Format("https://api.weixin.qq.com/cgi-bin/menu/delete?access_token={0}", access_token)).Result;
  297. if (!result.IsSuccessStatusCode) return "自定义菜单删除求失败...";
  298. return result.Content.ReadAsStringAsync().Result;
  299. }
  300. }
  301. }