LZ实在 不知道怎么起名字了,索性就取了这个名字,开始吧,说实在的,想给自己的平常的学习做一个总结,总是忘了总结。也只能给工作做一个总结了。

我打算用2篇文章来写,第一篇是关于订阅号的,就是这个号,另一篇是关于服务号的,到时候会介绍更多的东西,闲话不多,开始吧。

  首先,我们需要一个能创建自定义菜单的订阅号,微信的个人认证是不可能获得订阅号的,只有企业或者政府机构认证才可以申请。

首先我还是从创建菜单说起吧,创建菜单我们不需要进行服务器配置,我们只需要appid和appsecret就行了,这个东西从微信公众平台的后台进去,然后找到开发者中心。

如下图所示。

只有申请了认证的才可以活动APPID 和APPSECRET,然后我们来创建菜单吧,下面的APPID和APPSECRET将会用XXX代替,带来的不便请谅解。

首先我们需要在前台创建一个按钮,一个创建菜单的按钮,一个删除菜单的按钮。

这次因为赶时间,我把菜单给写死了,下一篇文章写的时候,我会展示给大家一个灵活的菜单。

下面是前台,就2个按钮,一个删除,一个添加修改按钮,针对订阅号。

  1. <div class="btn">
  2.  
  3. <div><asp:Button runat="server" ID="Add_Menu" OnClick="Add_Menu_Click" Text="创建(修改)菜单"/></div>
  4.  
  5. <div><asp:Button runat="server" ID="Del_Menu" OnClick="Del_Menu_Click" Text="删除菜单" OnClientClick="return confirm('是否删除菜单?')" />
  6. </div>

 后台代码我就一个一个解释吧。第一个为APPID和APPSECRET,

公众号有调用接口,第一个为授权,第二个为创建菜单的接口,第三个为删除菜单的接口。

如果有不懂的,可以参考官方API:http://mp.weixin.qq.com/wiki/index.php?title=%E9%A6%96%E9%A1%B5

  1. /*以下为订阅号*/
  2. static string appId = "XXXX";//公众号的appId
  3. static string appSecret = "XXXXX";//公众号的appSecret
  4.  
  5. /*以下为公共接口调用URL*/
  6. static string appUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential";
  7. static string postUrl = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=";
  8. static string postDelUrl = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token="; //删除菜单的URL

 我们要APPID和APPSECRET有什么作用呢?答案就是,我们要获得接入微信的一个凭证,而这个凭证,就是ACCESS_TOKEN.

下面是获得ACCESS_TOKEN的代码。具体的代码我也不是太懂,反正就是一个转化,有兴趣的可以自己测试一下,我就不多累赘了。

  1. //获得ACCESS_TOKEN,通过appid和app_secect获得(订阅号)
  2. public static string GetAccessToken()
  3. {
  4. WebClient webClient = new WebClient();
  5. Byte[] bytes = webClient.DownloadData(string.Format("{0}&appid={1}&secret={2}", appUrl, appId, appSecret));
  6. string result = Encoding.GetEncoding("utf-8").GetString(bytes);
  7.  
  8. //JObject jObj = JObject.Parse(result);
  9. //JToken token = jObj["access_token"];
  10. //return token.ToString().Substring(1, token.ToString().Length - 2);
  11.  
  12. string[] temp = result.Split(',');
  13. string[] tp = temp[0].Split(':');
  14. return tp[1].ToString().Replace('"', ' ').Trim().ToString();
  15.  
  16. }

  

下面是删除菜单的代码,主要 也是通过HTTP请求然后把请求转化成流的形式,然后把流读出来。

  1. private void DelMenu(string url)
  2. {
  3. if (string.IsNullOrEmpty(url))
  4. {
  5. throw new ArgumentNullException("url");
  6. }
  7. Encoding encoding = Encoding.UTF8;
  8. HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
  9. request.Method = "GET";
  10. HttpWebResponse response = request.GetResponse() as HttpWebResponse;
  11. Stream instream = response.GetResponseStream();
  12. StreamReader sr = new StreamReader(instream, encoding);
  13. string content = sr.ReadToEnd();
  14.  
  15. }

  

当然上面的删除是部分代码:

我们当然删除是通过微信给的URL去删除啦。

  1. //删除菜单(订阅号)
  2. protected void Del_Menu_Click(object sender, EventArgs e)
  3. {
  4. DelMenu(postDelUrl + GetAccessToken());
  5. }

下面我们来说一下怎么创建菜单,微信官方已经给我们提供了JSON的示例,如下图:

我也附上我自己的代码。

  1. //创建微信菜单JSON字符串
  2. public string GetWXMenuStr()
  3. {
  4. string weixin1 = "";
  5. weixin1 += "{\n";
  6. weixin1 += "\"button\":[\n";
  7. weixin1 += "{\n";
  8. // weixin1 += "\"type\":\"click\",\n";
  9. //第一个菜单
  10. weixin1 += "\"name\":\"公共信息\",\n";
  11. weixin1 += "\"sub_button\":[\n";
  12.  
  13. weixin1 += "{\n";
  14. weixin1 += "\"type\":\"click\",\n";
  15. weixin1 += "\"name\":\"通知公告\",\n";
  16. weixin1 += "\"key\":\"11\"\n";
  17. weixin1 += "},\n";
  18.  
  19. weixin1 += "{\n";
  20. weixin1 += "\"type\":\"click\",\n";
  21. weixin1 += "\"name\":\"工作动态\",\n";
  22. weixin1 += "\"key\":\"12\"\n";
  23. weixin1 += "},\n";
  24.  
  25. weixin1 += "{\n";
  26. weixin1 += "\"type\":\"click\",\n";
  27. weixin1 += "\"name\":\"政策法规\",\n";
  28. weixin1 += "\"key\":\"13\"\n";
  29. weixin1 += "},\n";
  30.  
  31. weixin1 += "{\n";
  32. weixin1 += "\"type\":\"click\",\n";
  33. weixin1 += "\"name\":\"经济视野\",\n";
  34. weixin1 += "\"key\":\"14\"\n";
  35. weixin1 += "},\n";
  36.  
  37. weixin1 += "{\n";
  38. weixin1 += "\"type\":\"click\",\n";
  39. weixin1 += "\"name\":\"专题报道\",\n";
  40. weixin1 += "\"key\":\"15\"\n";
  41. weixin1 += "}]\n";
  42. weixin1 += "},\n";
  43. //第二个菜单
  44. weixin1 += "{\n";
  45. //weixin1 += "\"type\":\"click\",\n";
  46. weixin1 += "\"name\":\"公共服务\",\n";
  47. weixin1 += "\"sub_button\":[\n";
  48. weixin1 += "{\n";
  49. weixin1 += "\"type\":\"click\",\n";
  50. weixin1 += "\"name\":\"企业之窗\",\n";
  51. weixin1 += "\"key\":\"21\"\n";
  52. weixin1 += "},\n";
  53.  
  54. weixin1 += "{\n";
  55. weixin1 += "\"type\":\"click\",\n";
  56. weixin1 += "\"name\":\"金融服务\",\n";
  57. weixin1 += "\"key\":\"22\"\n";
  58. weixin1 += "},\n";
  59.  
  60. weixin1 += "{\n";
  61. weixin1 += "\"type\":\"click\",\n";
  62. weixin1 += "\"name\":\"创业指导\",\n";
  63. weixin1 += "\"key\":\"23\"\n";
  64. weixin1 += "},\n";
  65.  
  66. weixin1 += "{\n";
  67. weixin1 += "\"type\":\"click\",\n";
  68. weixin1 += "\"name\":\"管理服务\",\n";
  69. weixin1 += "\"key\":\"24\"\n";
  70. weixin1 += "},\n";
  71.  
  72. weixin1 += "{\n";
  73. weixin1 += "\"type\":\"click\",\n";
  74. weixin1 += "\"name\":\"法律服务\",\n";
  75. weixin1 += "\"key\":\"25\"\n";
  76. weixin1 += "}]\n";
  77. weixin1 += "},\n";
  78. //第三个菜单(view类型的)
  79. weixin1 += "{\n";
  80. weixin1 += "\"name\":\"互动交流\",\n";
  81. weixin1 += "\"sub_button\":[\n";
  82. weixin1 += "{\n";
  83. weixin1 += "\"type\":\"view\",\n";
  84. weixin1 += "\"name\":\"服务信箱\",\n";
  85. weixin1 += "\"url\":\"http://www.baidu.com\"\n";
  86. weixin1 += "},\n";
  87.  
  88. weixin1 += "{\n";
  89. weixin1 += "\"type\":\"view\",\n";
  90. weixin1 += "\"name\":\"网上咨询\",\n";
  91. weixin1 += "\"url\":\"http://www.soso.com\"\n";
  92. weixin1 += "}]\n";
  93. weixin1 += "}\n";
  94. weixin1 += "}]\n";
  95.  
  96. weixin1 += "}\n";
  97. return weixin1;
  98. }

  需要注意的是,微信一级菜单只允许取3个,二级菜单最多5个,请大家注意。

下面是创建菜单的代码,说实在的我挺失败的,也是有点不求甚解,先放上来吧反正:

  1. /// <summary>
  2. ///
  3. /// </summary>
  4. /// <param name="url"></param>
  5. /// <param name="postData"></param>
  6. private void PostMenuData(string url, string postData)
  7. {
  8. Stream outstream = null;
  9. Stream instream = null;
  10. StreamReader sr = null;
  11. HttpWebResponse response = null;
  12. HttpWebRequest request = null;
  13. Encoding encoding = Encoding.UTF8;
  14. byte[] data = encoding.GetBytes(postData);
  15. // 准备请求...
  16. try
  17. {
  18. // 设置参数
  19. request = WebRequest.Create(url) as HttpWebRequest;
  20. CookieContainer cookieContainer = new CookieContainer();
  21. request.CookieContainer = cookieContainer;
  22. request.AllowAutoRedirect = true;
  23. request.Method = "POST";
  24. request.ContentType = "application/x-www-form-urlencoded";
  25. request.ContentLength = data.Length;
  26. outstream = request.GetRequestStream();
  27. outstream.Write(data, 0, data.Length);
  28. outstream.Close();
  29. //发送请求并获取相应回应数据
  30. response = request.GetResponse() as HttpWebResponse;
  31. //直到request.GetResponse()程序才开始向目标网页发送Post请求
  32. instream = response.GetResponseStream();
  33. sr = new StreamReader(instream, encoding);
  34. //返回结果网页(html)代码
  35. string content = sr.ReadToEnd();
  36. string err = string.Empty;
  37. // return content;
  38. }
  39. catch (Exception ex)
  40. {
  41. string err = ex.Message;
  42. //return string.Empty;
  43. }
  44. }

  下面点击添加按钮就执行如下方法:

  1. /// <summary>
  2. /// 创建自定义菜单(订阅号)
  3. /// </summary>
  4. private void CreateWxMenu()
  5. {
  6.  
  7. string weixin1=GetWXMenuStr();
  8.  
  9. PostMenuData(postUrl + GetAccessToken(), weixin1);
  10. }

  好了,到此我们的菜单就创建好了,下面来介绍一下如何给菜单添加事件,如果是VIEW类型的,只要给一个URL就行了,上面有写到,

如果是CLICK类型的,就要指定KEY,KEY是唯一的一个标识符。

不过在这之前,我们先要知道一点,微信必须要先有一个转发的文件,我们的微信和我们的网站的通信,就通过这个转发URL,打开开发者中心:

我们首先要启用服务器配置,把自己网站的那个转发文件配置进去,注意:微信只支持80端口,如果有一个订阅号,另一个服务号要用到的话,怎么办呢,写2个转发文件就够了。

废话不多说,如果你有条件的话,建议你去买一个云服务器做测试,我做测试是给公司买了一个云服务器的,坑死人,连报销都不给。

我这次是用的一个ASHX文件做转发,当然你也可以用ASPX文件,反正看自己喜好,那么我们还是来分析一下ASHX文件吧。

我们首先要知道,第一次进行验证的时候,肯定是要验证这个文件的,那么就要一个TOKEN,这个TOKEN只用验证一次,验证完了就没用了。

TOKEN是我们自己设置的,但是文件里的TOKEN要和服务器配置里的一样哦,而且验证通过了要启动服务器,这是很容易疏忽的,我都被忽悠了几次,哈哈。

因为第一次验证的时候的请求是GET的,如果验证通过了是POST的,所以我们可以在ProcessRequest方法这么写:

  1. public void ProcessRequest (HttpContext context) {
  2. //context.Response.ContentType = "text/plain";
  3. //context.Response.Write("Hello World");
  4. //以下代码只要用一次就行了,通过了就不必 再用了
  5. string postString = string.Empty;
  6. if (HttpContext.Current.Request.HttpMethod.ToUpper() == "GET")
  7. {
  8. string token = "123"; //填写微信服务端的TOKEN
  9.  
  10. if (string.IsNullOrEmpty(token))
  11. {
  12. return;
  13. }
  14.  
  15. string echoString = HttpContext.Current.Request.QueryString["echoStr"];
  16. string signature = HttpContext.Current.Request.QueryString["signature"];
  17. string timestamp = HttpContext.Current.Request.QueryString["timestamp"];
  18. string nonce = HttpContext.Current.Request.QueryString["nonce"];
  19.  
  20. if (!string.IsNullOrEmpty(echoString))
  21. {
  22. HttpContext.Current.Response.Write(echoString);
  23. HttpContext.Current.Response.End();
  24. }
  25.  
  26. }
  27.  
  28. else if (HttpContext.Current.Request.HttpMethod.ToUpper() == "POST")
  29. {
  30. using (Stream stream = HttpContext.Current.Request.InputStream)
  31. {
  32. Byte[] postBytes = new Byte[stream.Length];
  33. stream.Read(postBytes, 0, (Int32)stream.Length);
  34. postString = Encoding.UTF8.GetString(postBytes);
  35. Handle(postString);
  36. }
  37. }
  38.  
  39. }

  下面我们主要是以HANDEL方法为主线来看这个文件。

  1. /// <summary>
  2. /// 处理信息并应答
  3. /// </summary>
  4. private void Handle(string postStr)
  5. {
  6. //messageHelp help = new messageHelp();
  7.  
  8. string responseContent = ReturnMessage(postStr);
  9.  
  10. HttpContext.Current.Response.ContentEncoding = Encoding.UTF8;
  11. HttpContext.Current.Response.Write(responseContent);
  12. }

  其他的都可以无视,我们的重点主要是在这个ReturnMessage方法上面,就是说,微信服务端给我们传了一串字符串,我们的目的,就是把这串字符串解密。

试想一下,如果我们点击了微信菜单上了某一个内容,然后他会传字符串到我们这个ASHX文件中,如下,有可能是EVENT,事件,点击事件。

  1. //返回消息
  2. public string ReturnMessage(string postStr)
  3. {
  4. string responseContent = "";
  5. XmlDocument xmldoc = new XmlDocument();
  6. xmldoc.Load(new System.IO.MemoryStream(System.Text.Encoding.GetEncoding("GB2312").GetBytes(postStr)));
  7. XmlNode MsgType = xmldoc.SelectSingleNode("/xml/MsgType");
  8. if (MsgType != null)
  9. {
  10. switch (MsgType.InnerText)
  11. {
  12. case "event":
  13. responseContent = EventHandle(xmldoc);//事件处理
  14. break;
  15. case "text":
  16. responseContent = TextHandle(xmldoc);//接受文本消息处理
  17. break;
  18. default:
  19. break;
  20. }
  21. }
  22. return responseContent;
  23. }

  如果是事件的话,那么我们就需要返回这个事件处理之后的字符串,我们这次重点来看这个EvenHandler.关键是看前面的,我后面写了一些业务代码,

大家可以无视,都是关于ID的。大家想一下,我们创建菜单的时候,是不是指定过KEY,这里就可以用到哦,其中下面的ResponseContent也是返回字符串。

  1. public string EventHandle(XmlDocument xmldoc)
  2. {
  3. string responseContent = "";
  4. XmlNode Event = xmldoc.SelectSingleNode("/xml/Event");
  5. XmlNode EventKey = xmldoc.SelectSingleNode("/xml/EventKey");
  6. XmlNode ToUserName = xmldoc.SelectSingleNode("/xml/ToUserName");
  7. XmlNode FromUserName = xmldoc.SelectSingleNode("/xml/FromUserName");
  8. if (Event!=null)
  9. {
  10. //菜单单击事件
  11. if (Event.InnerText.Equals("CLICK"))
  12. {
  13. if (EventKey.InnerText.Equals("11"))//click_one
  14. {
  15. string typeid = "d19cace294e745fa8e38a8a1593703"; //类型ID:通知公告
  16.  
  17. responseContent = GetStrJsonDynamiclly(xmldoc, typeid);
  18. }
  19. else if (EventKey.InnerText.Equals("12"))//click_two
  20. {
  21. string typeid="dd2321c73d3946709c49f3fcb16d78"; //类型ID:工作动态
  22.  
  23. responseContent = GetStrJsonDynamiclly(xmldoc, typeid);
  24. }
  25. else if (EventKey.InnerText.Equals("13"))//click_three
  26. {
  27. string typeid = "3fbac2fbc0d44367a5358c80529e05"; //类型ID:政策法规
  28.  
  29. responseContent = GetStrJsonDynamiclly(xmldoc, typeid);
  30. }
  31.  
  32. else if (EventKey.InnerText.Equals("14"))//click_three
  33. {
  34. string typeid = "9c1fbf93601a4285a77614e9b1261f"; //类型ID:经济视野
  35.  
  36. responseContent = GetStrJsonDynamiclly(xmldoc, typeid);
  37. }
  38.  
  39. else if (EventKey.InnerText.Equals("15"))//click_three
  40. {
  41. string typeid = "14f0d6b7c4204035b82e3e83e81e59"; //类型ID:专题报道
  42.  
  43. responseContent = GetStrJsonDynamiclly(xmldoc, typeid);
  44. }
  45.  
  46. else if (EventKey.InnerText.Equals("21"))//click_three
  47. {
  48. string typeid = "ae6fc69cabfa4d059d5ba17bde1faf"; //类型ID:企业之窗
  49.  
  50. responseContent = GetStrJsonDynamiclly(xmldoc, typeid);
  51. }
  52. else if (EventKey.InnerText.Equals("22"))//click_three
  53. {
  54. string typeid = "fb86dbe3d7ed4df4850f7f24ce128b"; //类型ID:金融服务
  55.  
  56. responseContent = GetStrJsonDynamiclly(xmldoc, typeid);
  57. }
  58. else if (EventKey.InnerText.Equals("23"))//click_three
  59. {
  60. string typeid = "f961aa8accba454f840355f67cb492"; //类型ID:创业指导
  61.  
  62. responseContent = GetStrJsonDynamiclly(xmldoc, typeid);
  63. }
  64. else if (EventKey.InnerText.Equals("24"))//click_three
  65. {
  66. string typeid = "0e5033c616214fe484cdff377741b3"; //类型ID:管理服务
  67.  
  68. responseContent = GetStrJsonDynamiclly(xmldoc, typeid);
  69. }
  70. else if (EventKey.InnerText.Equals("25"))//click_three
  71. {
  72. string typeid = "6f22bdf17708471e840a653931d4ec"; //类型ID:法律服务
  73.  
  74. responseContent = GetStrJsonDynamiclly(xmldoc, typeid);
  75. }
  76.  
  77. }
  78. }
  79. return responseContent;
  80. }

  上面的是GetStrJsonDynamiclly方法的掠影,主要是业务逻辑,大家可以参考下。

  1. //获得要上传到服务器的字符串,其中的typeid为动态值
  2. public string GetStrJsonDynamiclly(XmlDocument xmldoc,string typeid)
  3. {
  4.  
  5. string responseContent = "";
  6. XmlNode Event = xmldoc.SelectSingleNode("/xml/Event");
  7. XmlNode EventKey = xmldoc.SelectSingleNode("/xml/EventKey");
  8. XmlNode ToUserName = xmldoc.SelectSingleNode("/xml/ToUserName");
  9. XmlNode FromUserName = xmldoc.SelectSingleNode("/xml/FromUserName");
  10. string picUrl = ""; //图片地址;
  11. string basicPicUrl = "http://XXX/XXX/pic/";
  12. //创业指导
  13.  
  14. if (typeid == "f961aa8accba454f840355f67cb492")
  15. {
  16. picUrl = basicPicUrl + "cyzd.jpg";
  17. }
  18. //法律服务
  19. else if (typeid == "6f22bdf17708471e840a653931d4ec")
  20. {
  21. picUrl = basicPicUrl + "flfw.jpg";
  22. }
  23.  
  24. string strJson = string.Format(ReplyType.Message_News_Main,
  25. FromUserName.InnerText,
  26. ToUserName.InnerText,
  27. DateTime.Now.Ticks,
  28. "6",
  29. string.Format(ReplyType.Message_News_Item, GetDataByIndex(1, typeid), "",
  30. picUrl,
  31. basicIP + GetArticleParams(1, typeid)[0]) +
  32. string.Format(ReplyType.Message_News_Item, GetDataByIndex(2, typeid), "",
  33. "",
  34. basicIP + GetArticleParams(2, typeid)[0])
  35. +
  36. string.Format(ReplyType.Message_News_Item, GetDataByIndex(3, typeid), "",
  37. "",
  38. basicIP + GetArticleParams(3, typeid)[0]) +
  39. string.Format(ReplyType.Message_News_Item, GetDataByIndex(4, typeid), "",
  40. "",
  41. basicIP + GetArticleParams(4, typeid)[0]) +
  42. string.Format(ReplyType.Message_News_Item, GetDataByIndex(5, typeid), "",
  43. "",
  44. basicIP + GetArticleParams(5, typeid)[0]) +
  45. string.Format(ReplyType.Message_News_Item, GetDataByIndex(6, typeid), "",
  46. "",
  47. basicIP + GetArticleParams(6, typeid)[0]));
  48. return strJson;
  49.  
  50. }

  

总之,上面的代码只有一个目的,就是返回字符串,比如点击微信的菜单,可以返回6篇文章,其中可以给文章指定背景图片。其中的方法是获取URL和文章标题的,具体就不累赘了,根据自己的业务具体来办。

另外还给大家提供3个工具方法:

大家根据需求自由使用,具体的完全的代码,我就不给哦。

  1. //写入日志
  2. public void WriteLog(string text)
  3. {
  4. StreamWriter sw = new StreamWriter(HttpContext.Current.Server.MapPath(".") + "\\log.txt", true);
  5. sw.WriteLine(text);
  6. sw.Close();//写入
  7. }
  8. }
  9.  
  10. //回复类型
  11. public class ReplyType
  12. {
  13. /// <summary>
  14. /// 普通文本消息
  15. /// </summary>
  16. public static string Message_Text
  17. {
  18. get
  19. {
  20. return @"<xml>
  21. <ToUserName><![CDATA[{0}]]></ToUserName>
  22. <FromUserName><![CDATA[{1}]]></FromUserName>
  23. <CreateTime>{2}</CreateTime>
  24. <MsgType><![CDATA[text]]></MsgType>
  25. <Content><![CDATA[{3}]]></Content>
  26. </xml>";
  27. }
  28. }
  29. /// <summary>
  30. /// 图文消息主体
  31. /// </summary>
  32. public static string Message_News_Main
  33. {
  34. get
  35. {
  36. return @"<xml>
  37. <ToUserName><![CDATA[{0}]]></ToUserName>
  38. <FromUserName><![CDATA[{1}]]></FromUserName>
  39. <CreateTime>{2}</CreateTime>
  40. <MsgType><![CDATA[news]]></MsgType>
  41. <ArticleCount>{3}</ArticleCount>
  42. <Articles>
  43. {4}
  44. </Articles>
  45. </xml> ";
  46. }
  47. }
  48. /// <summary>
  49. /// 图文消息项
  50. /// </summary>
  51. public static string Message_News_Item
  52. {
  53. get
  54. {
  55. return @"<item>
  56. <Title><![CDATA[{0}]]></Title>
  57. <Description><![CDATA[{1}]]></Description>
  58. <PicUrl><![CDATA[{2}]]></PicUrl>
  59. <Url><![CDATA[{3}]]></Url>
  60. </item>";
  61. }
  62. }

好了,这一篇因为时间和技术原因就介绍到这里了,过1,2个星期我将会把灵活在后台配置菜单以及服务号C#后台推送图文消息跟大家讲清楚。

ASP.NET实现微信功能(1)(创建菜单,验证,给菜单添加事件)的更多相关文章

  1. ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇

    原文:ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇 第三章 为控件添加事件 好了,我们之前以前开发一个控件.而且也添加了属性,开发也很规范,但是那个控件还差最后一点:添加事件. 系列 ...

  2. ASP.NET自定义控件组件开发 第三章 为控件添加事件 后篇

    原文:ASP.NET自定义控件组件开发 第三章 为控件添加事件 后篇 第三章 为控件添加事件 后篇 前一篇文章只是简单的说了下事件,但是大家应该方法,在ASP.NET自定义控件中只是简单那么定义事件是 ...

  3. ASP.NET MVC 微信公共平台开发之验证消息的真实性

    ASP.NET MVC 微信公共平台开发 验证消息的真实性 在MVC Controller所在项目中添加过滤器,在过滤器中重写 public override void OnActionExecuti ...

  4. ASP.NET实现微信功能(2)(服务号高级群发)

    前面写了一篇文章,关于微信的:http://www.cnblogs.com/kmsfan/p/4047097.html 今天打算来写本系列的第二批文章,服务号后台群发. 在写本篇文章之前,我们先来看看 ...

  5. [c#]asp.net开发微信公众平台(8)微信9大高级接口,自定义菜单

    前7篇把最基础的消息接收和回复全做完了,  也把高级接口的入口和分拆处理写好了空方法,  此篇接着介绍微信的9大高级接口, 并着重讲解其中的自定义菜单. 微信9大接口为: 1.语音识别接口 2.客服接 ...

  6. 微信程序开发系列教程(四)使用微信API创建公众号自定义菜单

    大家可能经常看到一些微信公众号具有功能强大的自定义菜单,点击之后可以访问很多有用的功能. 这篇教程就教大家如何动手做一做. 这个教程最后实现的效果是:创建一个一级菜单"UI5", ...

  7. C#/ASP.NET MVC微信公众号接口开发之从零开发(四) 微信自定义菜单(附源码)

    C#/ASP.NET MVC微信接口开发文章目录: 1.C#/ASP.NET MVC微信公众号接口开发之从零开发(一) 接入微信公众平台 2.C#/ASP.NET MVC微信公众号接口开发之从零开发( ...

  8. asp.net 输出微信自定义菜单json

    这里使用LitJson.dll作json解析. 微信规定的自定义菜单json样式如下: { "button":[ { "type":"click&qu ...

  9. asp.net 仿微信端菜单设置

    第一步:添加引用文件 <link rel="stylesheet" href="~/assets/css/bootstrap.min.css"> & ...

随机推荐

  1. php中htmlspecialchars()函数和addslashes()函数的使用和区别

    在防止被注入攻击时,常会用到两个函数:htmlspecialchars()和addslashes()函数.这两个函数都是对特殊字符进行转义. 1)addslashes()作用及使用 addslashe ...

  2. ntfs-3g

    CentOS默认源里没有ntfs3g,想要添加ntfs支持,无非是自己下载编译安装或者加源yum安装. 昨天重新安装了一个CentOS7,用的是添加aliyun的epel源来yum安装的方式,简单易行 ...

  3. Java中有关Null的9件事

    对于Java程序员来说,null是令人头痛的东西.时常会受到空指针异常 (NPE)的骚扰.连Java的发明者都承认这是他的一项巨大失误.Java为什么要保留null呢?null出现有一段时间了,并且我 ...

  4. Third Day(上班第四天):Android开发环境配置问题相关

    换公司新电脑了,重新安装Android开发环境,并配置,具体流程如下:1.百度JDK,访问Oracle官网:http://www.oracle.com/technetwork/java/javase/ ...

  5. Web应用程序的自动化测试库-FluentAutomation

    FluentAutomation是流畅的自动化应用编程接口,支持Selenium和WatiN 连同它们所有的风格和驱动程序.自从Fluient支持Selenium,那就意味着你可以使用Selenium ...

  6. 控制ASP.NET Web API 调用频率

    很多的api,例如GitHub’s API 都有流量控制的做法.使用速率限制,以防止在很短的时间量客户端向你的api发出太多的请求.例如,我们可以限制匿名API客户端每小时最多60个请求,而我们可以让 ...

  7. 自己动手写一个简单的MVC框架(第二版)

    一.ASP.NET MVC核心机制回顾 在ASP.NET MVC中,最核心的当属“路由系统”,而路由系统的核心则源于一个强大的System.Web.Routing.dll组件. 在这个System.W ...

  8. CSS尺寸和字体单位-em、px还是%

    在页面整体布局中,页面元素的尺寸大小(长度.宽度.内外边距等)和页面字体的大小也是重要的工作之一.一个合理设置,则会让页面看起来层次分明,重点鲜明,赏心悦目.反之,一个不友好的页面尺寸和字体大小设置, ...

  9. Windows Azure Storage (6) Windows Azure Storage之Table

    <Windows Azure Platform 系列文章目录> 最近想了想,还是有必要把Windows Azure Table Storage 给说清楚. 1.概念 Windows Azu ...

  10. [公告]Senparc.Weixin v4.7.0 升级说明(2016-08-08)

    本次升级包含了除QY以外所有的类库,升级内容包括: 1.重构Conatainer结构,删除 ItemCollection 属性,直接使用ContainerBag加入到缓存: 2.重构IContaine ...