微信公共服务平台开发(.Net 的实现)

来源:互联网 发布:bloom filter python 编辑:程序博客网 时间:2024/04/27 20:06

微信公共服务平台开发(.Net 的实现)1-------认证“成为开发者”

这些代码也就开始认证的时候用一次,以后就不用了:


[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. const string Token = "XXXXX";//你的token  
  2. protected void Page_Load(object sender, EventArgs e)  
  3. {  
  4.     string postStr = "";  
  5.     if (Request.HttpMethod.ToLower() == "post")  
  6.     {  
  7.         System.IO.Stream s = System.Web.HttpContext.Current.Request.InputStream;  
  8.         byte[] b = new byte[s.Length];  
  9.         s.Read(b, 0, (int)s.Length);  
  10.         postStr = System.Text.Encoding.UTF8.GetString(b);  
  11.         if (!string.IsNullOrEmpty(postStr))  
  12.         {  
  13.             //ResponseMsg(postStr);  
  14.             Response.Write(ResponseMsg(postStr));  
  15.             Response.End();  
  16.         }  
  17.         //WriteLog("postStr:" + postStr);  
  18.     }  
  19.     else  
  20.     {  
  21.         Valid();  
  22.     }  
  23. }       
  24.   
  25. /// <summary>  
  26. /// 验证微信签名  
  27. /// </summary>  
  28. /// * 将token、timestamp、nonce三个参数进行字典序排序  
  29. /// * 将三个参数字符串拼接成一个字符串进行sha1加密  
  30. /// * 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信。  
  31. /// <returns></returns>  
  32. private bool CheckSignature()  
  33. {  
  34.     string signature = Request.QueryString["signature"].ToString();  
  35.     string timestamp = Request.QueryString["timestamp"].ToString();  
  36.     string nonce = Request.QueryString["nonce"].ToString();  
  37.     string[] ArrTmp = { Token, timestamp, nonce };  
  38.     Array.Sort(ArrTmp);     //字典排序  
  39.     string tmpStr = string.Join("", ArrTmp);  
  40.     tmpStr = FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1");  
  41.     tmpStr = tmpStr.ToLower();  
  42.     if (tmpStr == signature)  
  43.     {  
  44.         return true;  
  45.     }  
  46.     else  
  47.     {  
  48.         return false;  
  49.     }  
  50. }  
  51.   
  52.   
  53. private void Valid()  
  54. {  
  55.     string echoStr = Request.QueryString["echoStr"].ToString();  
  56.     if (CheckSignature())  
  57.     {  
  58.         if (!string.IsNullOrEmpty(echoStr))  
  59.         {  
  60.             Response.Write(echoStr);  
  61.             Response.End();  
  62.         }  
  63.     }  
  64. }       
  65.   
  66.   
  67. /// <summary>  
  68. /// 写日志(用于跟踪)  
  69. /// </summary>  
  70. private void WriteLog(string strMemo)  
  71. {  
  72.     string filename = Server.MapPath("/logs/log.txt");  
  73.     if (!Directory.Exists(Server.MapPath("//logs//")))  
  74.         Directory.CreateDirectory("//logs//");  
  75.     StreamWriter sr = null;  
  76.     try  
  77.     {  
  78.         if (!File.Exists(filename))  
  79.         {  
  80.             sr = File.CreateText(filename);  
  81.         }  
  82.         else  
  83.         {  
  84.             sr = File.AppendText(filename);  
  85.         }  
  86.         sr.WriteLine(strMemo);  
  87.     }  
  88.     catch  
  89.     {  
  90.   
  91.     }  
  92.     finally  
  93.     {  
  94.         if (sr != null)  
  95.             sr.Close();  
  96.     }  


成为了开发者之后微信平台会给您appid和secret,在订阅号中是没有的,所以因该申请一下服务号

有了ACCESSTOKEN才能做添加菜单,上传/下载图片等功能

[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private string GetToken()  
  2.      {  
  3.   
  4.          // 也可以这样写:  
  5.          //return  GetPage("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=你的appid&secret=你的secret", "");  
  6.          
  7.          string res = "";  
  8.          HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential  
  9. &appid=你的appid&secret=你的secret");  
  10.  req.Method = "GET";  
  11.          using (WebResponse wr = req.GetResponse())  
  12.          {  
  13.              HttpWebResponse myResponse = (HttpWebResponse)req.GetResponse();  
  14.   
  15.   
  16.              StreamReader reader = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8);  
  17.   
  18.   
  19.              string content = reader.ReadToEnd();  
  20.      
  21.              List<ACCESSTOKEN> myACCESSTOKEN = Json.JSONStringToList<ACCESSTOKEN>(content);  
  22.              res = myACCESSTOKEN[0].access_token;  
  23.    
  24.          }  
  25.   
  26.   
  27.          return res;  
  28.      }  
  29.      public string GetPage(string posturl, string postData)  
  30.      {  
  31.          Stream outstream = null;  
  32.          Stream instream = null;  
  33.          StreamReader sr = null;  
  34.          HttpWebResponse response = null;  
  35.          HttpWebRequest request = null;  
  36.          Encoding encoding = Encoding.UTF8;  
  37.          byte[] data = encoding.GetBytes(postData);  
  38.          // 准备请求...  
  39.          try  
  40.          {  
  41.              // 设置参数  
  42.              request = WebRequest.Create(posturl) as HttpWebRequest;  
  43.              CookieContainer cookieContainer = new CookieContainer();  
  44.              request.CookieContainer = cookieContainer;  
  45.              request.AllowAutoRedirect = true;  
  46.              request.Method = "POST";  
  47.              request.ContentType = "application/x-www-form-urlencoded";  
  48.              request.ContentLength = data.Length;  
  49.              outstream = request.GetRequestStream();  
  50.              outstream.Write(data, 0, data.Length);  
  51.              outstream.Close();  
  52.              //发送请求并获取相应回应数据  
  53.              response = request.GetResponse() as HttpWebResponse;  
  54.              //直到request.GetResponse()程序才开始向目标网页发送Post请求  
  55.              instream = response.GetResponseStream();  
  56.              sr = new StreamReader(instream, encoding);  
  57.              //返回结果网页(html)代码  
  58.              string content = sr.ReadToEnd();  
  59.              string err = string.Empty;  
  60.              return content;  
  61.          }  
  62.          catch (Exception ex)  
  63.          {  
  64.              string err = ex.Message;  
  65.              Response.Write(err);  
  66.              return string.Empty;  
  67.          }  
  68.      }  

首先建立一个微信消息类。

[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class wxmessage    
  2.   {    
  3.       public string FromUserName { getset; }    
  4.       public string ToUserName { getset; }    
  5.        public string MsgType { getset; }    
  6.        public string EventName { getset; }    
  7.        public string Content { getset; }  
  8.        public string EventKey { getset; }   
  9.    }  


后台代码如下:


[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. protected void Page_Load(object sender, EventArgs e)  
  2.      {  
  3.          wxmessage wx = GetWxMessage();  
  4.          string res = "";  
  5.   
  6.          if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.Trim() == "subscribe")  
  7.          {//刚关注时的时间,用于欢迎词  
  8.              string content = "";  
  9.              content = "/:rose欢迎北京永杰友信科技有限公司/:rose\n直接回复“你好”";  
  10.              res = sendTextMessage(wx, content);  
  11.          }  
  12.          else  
  13.          {  
  14.              if (wx.MsgType == "text" && wx.Content == "你好")  
  15.              {  
  16.                  res = sendTextMessage(wx, "你好,欢迎使用北京永杰友信科技有限公司公共微信平台!");  
  17.              }  
  18.              else  
  19.              {  
  20.                  res = sendTextMessage(wx, "你好,未能识别消息!");  
  21.              }  
  22.          }  
  23.   
  24.          Response.Write(res);  
  25.      }  
  26.   
  27.  private wxmessage GetWxMessage()  
  28.      {  
  29.          wxmessage wx = new wxmessage();  
  30.          StreamReader str = new StreamReader(Request.InputStream, System.Text.Encoding.UTF8);  
  31.          XmlDocument xml = new XmlDocument();  
  32.          xml.Load(str);  
  33.          wx.ToUserName = xml.SelectSingleNode("xml").SelectSingleNode("ToUserName").InnerText;  
  34.          wx.FromUserName = xml.SelectSingleNode("xml").SelectSingleNode("FromUserName").InnerText;  
  35.          wx.MsgType = xml.SelectSingleNode("xml").SelectSingleNode("MsgType").InnerText;  
  36.          if (wx.MsgType.Trim() == "text")  
  37.          {  
  38.              wx.Content = xml.SelectSingleNode("xml").SelectSingleNode("Content").InnerText;  
  39.          }  
  40.          if (wx.MsgType.Trim() == "event")  
  41.          {  
  42.              wx.EventName = xml.SelectSingleNode("xml").SelectSingleNode("Event").InnerText;  
  43.          }  
  44.   
  45.            
  46.          return wx;  
  47.      }  
  48.   
  49. /// <summary>    
  50.      /// 发送文字消息    
  51.      /// </summary>    
  52.      /// <param name="wx">获取的收发者信息    
  53.      /// <param name="content">内容    
  54.      /// <returns></returns>    
  55.      private string sendTextMessage(wxmessage wx, string content)  
  56.      {  
  57.          string res = string.Format(@" ",  
  58.              wx.FromUserName, wx.ToUserName, DateTime.Now, content);  
  59.          return res;  
  60.      }  


语音识别这个功能属于高级功能,必须微信实名认证后才能实现,认证费用300元/年,如果你作为开发者可以申请测试帐号,也是可以的。首先建立一个微信消息类,这个类比之前多了一个属性。

[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class wxmessage    
  2.   {    
  3.       public string FromUserName { getset; }    
  4.       public string ToUserName { getset; }    
  5.        public string MsgType { getset; }    
  6.        public string EventName { getset; }    
  7.        public string Content { getset; }  
  8.        public string Recognition { getset; }  
  9.        public string EventKey { getset; }   
  10.    }  


语音识别是微信自带的功能,非常强大无需我们做过多的操作:


[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. protected void Page_Load(object sender, EventArgs e)  
  2.      {  
  3.          wxmessage wx = GetWxMessage();  
  4.          string res = "";  
  5.   
  6.          if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.Trim() == "subscribe")  
  7.          {//刚关注时的时间,用于欢迎词  
  8.              string content = "";  
  9.              content = "/:rose欢迎北京永杰友信科技有限公司/:rose\n直接回复“你好”";  
  10.              res = sendTextMessage(wx, content);  
  11.          }  
  12.          else  
  13.          {  
  14.              if (wx.MsgType == "text" && wx.Content == "你好")  
  15.              {  
  16.                  res = sendTextMessage(wx, "你好,欢迎使用北京永杰友信科技有限公司公共微信平台!");  
  17.              }  
  18.              else if (wx.MsgType == "voice")//识别消息类型为语音  
  19.              {  
  20.                  res = sendTextMessage(wx, wx.Recognition);//wx.Recognition就是语音识别的结果了,我们直接引用,以文本形式反馈就OK了  
  21.   
  22.              }  
  23.              else  
  24.              {  
  25.                  res = sendTextMessage(wx, "你好,未能识别消息!");  
  26.              }  
  27.          }  
  28.   
  29.          Response.Write(res);  
  30.      }  
  31.   
  32.  private wxmessage GetWxMessage()  
  33.      {  
  34.          wxmessage wx = new wxmessage();  
  35.          StreamReader str = new StreamReader(Request.InputStream, System.Text.Encoding.UTF8);  
  36.          XmlDocument xml = new XmlDocument();  
  37.          xml.Load(str);  
  38.          wx.ToUserName = xml.SelectSingleNode("xml").SelectSingleNode("ToUserName").InnerText;  
  39.          wx.FromUserName = xml.SelectSingleNode("xml").SelectSingleNode("FromUserName").InnerText;  
  40.          wx.MsgType = xml.SelectSingleNode("xml").SelectSingleNode("MsgType").InnerText;  
  41.          if (wx.MsgType.Trim() == "text")  
  42.          {  
  43.              wx.Content = xml.SelectSingleNode("xml").SelectSingleNode("Content").InnerText;  
  44.          }  
  45.          if (wx.MsgType.Trim() == "event")  
  46.          {  
  47.              wx.EventName = xml.SelectSingleNode("xml").SelectSingleNode("Event").InnerText;  
  48.          }  
  49.          if (wx.MsgType.Trim() == "voice")//如果是语音消息的话就把识别结果赋值给实体类的相应属性Recognition   
  50.          {  
  51.              wx.Recognition = xml.SelectSingleNode("xml").SelectSingleNode("Recognition").InnerText;  
  52.          }  
  53.            
  54.          return wx;  
  55.      }  
  56.   
  57.   
  58.      /// <summary>    
  59.      /// 发送文字消息    
  60.      /// </summary>    
  61.      /// <param name="wx">获取的收发者信息    
  62.      /// <param name="content">内容    
  63.      /// <returns></returns>    
  64.      private string sendTextMessage(wxmessage wx, string content)  
  65.      {  
  66.          string res = string.Format(@" ",  
  67.              wx.FromUserName, wx.ToUserName, DateTime.Now, content);  
  68.          return res;  
  69.      }  

更多0
因为access_token,在以后的高级功能里面会经常用到,所以这里不得不这里对前面所讲解的access_token改造一下。
另外需要说明的是access_token是变化的,有自己的周期,官方解释为:"有效期为7200秒",这就要


求我们把获得的access_token存入一个物理文件或者Application中,请求到过期后修改这些内容,需要用的时候读出来.
有些人可能想到了,如果过期我就在获得一个就好了,不用物理文件和Application也可以达到同样的效果,但是需要注意了微信平台对每天获得


access_token的次数也作了限制,一个用户出发多次,如果用户多,那肯定就超出了。所以我们还是按照以上的思路实现这些功能:
在此之前我们已经了解了获得access_token的方法(连接),现在只需要保证它的随时更新就好了.


首先建立一个Access_token类

[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /// <summary>  
  2. ///Access_token 的摘要说明  
  3. /// </summary>  
  4. public class Access_token  
  5. {  
  6.     public Access_token()  
  7.     {  
  8.         //  
  9.         //TODO: 在此处添加构造函数逻辑  
  10.         //  
  11.     }  
  12.     string _access_token;  
  13.     string _expires_in;  
  14.   
  15.     /// <summary>  
  16.     /// 获取到的凭证   
  17.     /// </summary>  
  18.     public string access_token  
  19.     {  
  20.         get { return _access_token; }  
  21.         set { _access_token = value; }  
  22.     }  
  23.   
  24.     /// <summary>  
  25.     /// 凭证有效时间,单位:秒  
  26.     /// </summary>  
  27.     public string expires_in  
  28.     {  
  29.         get { return _expires_in; }  
  30.         set { _expires_in = value; }  
  31.     }  
  32. }  

用下面的XML文件来存放access_token,建立一个XMLFile.xml,把Access_YouXRQ标签的内容写成一个已经过去的时间,这样我们好在一开始调用的时候,发现已经过期,然后获取新的access_token。
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <xml>  
  3.   <Access_Token>初始值可以随便写</Access_Token>  
  4.   <Access_YouXRQ>1980/12/12 16:06:38</Access_YouXRQ>  
  5. </xml>  

改造一下之前获得Access_token的方法,让他给Access_token实例赋值
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public static Access_token GetAccess_token()  
  2.     {  
  3.         string appid = 你的appid ;  
  4.         string secret = 你的secret;  
  5.         string strUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret;  
  6.         Access_token mode = new Access_token();  
  7.   
  8.         HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(strUrl);  
  9.   
  10.         req.Method = "GET";  
  11.         using (WebResponse wr = req.GetResponse())  
  12.         {  
  13.             HttpWebResponse myResponse = (HttpWebResponse)req.GetResponse();  
  14.   
  15.             StreamReader reader = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8);  
  16.   
  17.             string content = reader.ReadToEnd();  
  18.             //Response.Write(content);  
  19.             //在这里对Access_token 赋值  
  20.             Access_token token = new Access_token();  
  21.             token = JsonHelper.ParseFromJson<Access_token>(content);  
  22.             mode.access_token = token.access_token;  
  23.             mode.expires_in = token.expires_in;  
  24.         }  
  25.         return mode;  
  26.     }  

以上的方法用到了Json对象的处理,所以我把JsonHelper的代码一贴出来供大家参考,一下就是JsonHelper.cs的代码:


[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. using System;  
  2. using System.IO;  
  3. using System.Text;  
  4. using System.Runtime.Serialization.Json;  
  5.    
  6.    
  7.   
  8. public class JsonHelper  
  9. {  
  10.     /// <summary>  
  11.     /// 生成Json格式  
  12.     /// </summary>  
  13.     /// <typeparam name="T"></typeparam>  
  14.     /// <param name="obj"></param>  
  15.     /// <returns></returns>  
  16.     public static string GetJson<T>(T obj)  
  17.     {  
  18.         DataContractJsonSerializer json = new DataContractJsonSerializer(obj.GetType());  
  19.         using (MemoryStream stream = new MemoryStream())  
  20.         {  
  21.             json.WriteObject(stream, obj);  
  22.             string szJson = Encoding.UTF8.GetString(stream.ToArray()); return szJson;  
  23.         }  
  24.     }  
  25.     /// <summary>  
  26.     /// 获取Json的Model  
  27.     /// </summary>  
  28.     /// <typeparam name="T"></typeparam>  
  29.     /// <param name="szJson"></param>  
  30.     /// <returns></returns>  
  31.     public static T ParseFromJson<T>(string szJson)  
  32.     {  
  33.         T obj = Activator.CreateInstance<T>();  
  34.         using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(szJson)))  
  35.         {  
  36.             DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());  
  37.             return (T)serializer.ReadObject(ms);  
  38.         }  
  39.     }  
  40. }  

我们还需要些一个判断access_token是否过期如果过期更新XML文件的方法。
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /// <summary>  
  2.     /// 根据当前日期 判断Access_Token 是否超期  如果超期返回新的Access_Token   否则返回之前的Access_Token  
  3.     /// </summary>  
  4.     /// <param name="datetime"></param>  
  5.     /// <returns></returns>  
  6.     public static string IsExistAccess_Token()  
  7.     {  
  8.   
  9.         string Token = string.Empty;  
  10.         DateTime YouXRQ;  
  11.         // 读取XML文件中的数据,并显示出来 ,注意文件路径  
  12.         string filepath = Server.MapPath("XMLFile.xml");  
  13.   
  14.         StreamReader str = new StreamReader(filepath, System.Text.Encoding.UTF8);  
  15.         XmlDocument xml = new XmlDocument();  
  16.         xml.Load(str);  
  17.         str.Close();  
  18.         str.Dispose();  
  19.         Token = xml.SelectSingleNode("xml").SelectSingleNode("Access_Token").InnerText;  
  20.         YouXRQ = Convert.ToDateTime(xml.SelectSingleNode("xml").SelectSingleNode("Access_YouXRQ").InnerText);  
  21.   
  22.         if (DateTime.Now > YouXRQ)  
  23.         {  
  24.             DateTime _youxrq = DateTime.Now;  
  25.             Access_token mode = GetAccess_token();  
  26.             xml.SelectSingleNode("xml").SelectSingleNode("Access_Token").InnerText = mode.access_token;  
  27.             _youxrq = _youxrq.AddSeconds(int.Parse(mode.expires_in));  
  28.             xml.SelectSingleNode("xml").SelectSingleNode("Access_YouXRQ").InnerText = _youxrq.ToString();  
  29.             xml.Save(filepath);  
  30.             Token = mode.access_token;  
  31.         }  
  32.         return Token;  
  33.     }  



好了,完成了上面的工作,我只需要在使用到access_token的时如下调用就OK了,“客户再也不用担心token的过期”


string _access_token = IsExistAccess_Token();
更多0

用户自定义菜单制作时,需要用到access_token,我们直接使用前面讲解的IsExistAccess_Token()函数。我理解的微信公共平台里面菜单分为button和sub_button,即菜单和子菜单,这些菜单都有一个name的属性,类别分为click和view,click类有key属性;而view类有url属性,含有子菜单的菜单没有key属性也没有url属性。这些情况可以从下面的例子看出来。

[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1.  public void MyMenu()  
  2.      {  
  3.          string weixin1 = "";  
  4.          weixin1 = @" {  
  5.      ""button"":[  
  6.      {    
  7.           ""type"":""click"",  
  8.           ""name"":""你好!"",  
  9.           ""key"":""Hello""  
  10.       },  
  11.       {  
  12.            ""type"":""view"",  
  13.            ""name"":""公司简介"",  
  14.            ""url"":""http://www.4ugood.net""  
  15.       },  
  16.       {  
  17.            ""name"":""产品介绍"",  
  18.            ""sub_button"":[  
  19.             {  
  20.                ""type"":""click"",  
  21.                ""name"":""产品1"",  
  22.                 ""key"":""P1""  
  23.             },  
  24.             {  
  25.                ""type"":""click"",  
  26.                ""name"":""产品2"",  
  27.                ""key"":""P2""  
  28.             }]  
  29.        }]  
  30.  }  
  31. ";  
  32.   
  33.          string access_token = IsExistAccess_Token();  
  34.          string i = GetPage("https://api.weixin.qq.com/cgi-bin/menu/create?access_token="+access_token, weixin1);  
  35.          Response.Write(i);  
  36.      }  
在你页面的 Page_Load 函数中调用这个MyMenu(),就可以显示出来了。
既然显示出来了,菜单的时间如何出发呢?我们已经了解到了如果类型为view的话,他有url属性,这个不需要处理,点击后会直接跳转到你设定的url的页面,下面我来看看如何触发click吧,按照微信的文档可以用(!string.IsNullOrEmpty(wx.EventName) && wx.EventName.Trim() == "CLICK")来判断,我把之前的代码改造一下,同时把在GetWxMessage()方法中把EventKey的值附上,wx.EventKey = xml.SelectSingleNode("xml").SelectSingleNode("EventKey").InnerText; 
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. protected void Page_Load(object sender, EventArgs e)  
  2.      {  
  3.           
  4.          MyMenu();  
  5.          wxmessage wx = GetWxMessage();  
  6.          string res = "";  
  7.   
  8.          if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.Trim() == "subscribe")  
  9.          {  
  10.              string content = "";  
  11.              content = "/:rose欢迎北京永杰友信科技有限公司/:rose\n直接回复“你好”";  
  12.              res = sendTextMessage(wx, content);  
  13.          }  
  14.          else if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.Trim() == "CLICK")  
  15.          {  
  16.              if(wx.EventKey=="Hello")  
  17.                  res = sendTextMessage(wx, "你好,欢迎使用北京永杰友信科技有限公司公共微信平台!");  
  18.              if(wx.EventKey=="P1")  
  19.                  res = sendTextMessage(wx, "你好,点击了产品1");  
  20.              if(wx.EventKey=="P2")  
  21.                  res = sendTextMessage(wx, "你好,点击了产品2");  
  22.          }  
  23.          else  
  24.          {  
  25.              if (wx.MsgType == "text" && wx.Content == "你好")  
  26.              {  
  27.                  res = sendTextMessage(wx, "你好,欢迎使用北京永杰友信科技有限公司公共微信平台!");  
  28.              }  
  29.              else if (wx.MsgType == "voice")  
  30.              {  
  31.                  res = sendTextMessage(wx, wx.Recognition);  
  32.              }  
  33.              else  
  34.              {  
  35.                  res = sendTextMessage(wx, "你好,未能识别消息!");  
  36.              }  
  37.          }  
  38.   
  39.          Response.Write(res);  
  40.      }  
  41.   
  42.   
  43.   
  44.      private wxmessage GetWxMessage()  
  45.      {  
  46.          wxmessage wx = new wxmessage();  
  47.          StreamReader str = new StreamReader(Request.InputStream, System.Text.Encoding.UTF8);  
  48.          XmlDocument xml = new XmlDocument();  
  49.          xml.Load(str);  
  50.          wx.ToUserName = xml.SelectSingleNode("xml").SelectSingleNode("ToUserName").InnerText;  
  51.          wx.FromUserName = xml.SelectSingleNode("xml").SelectSingleNode("FromUserName").InnerText;  
  52.          wx.MsgType = xml.SelectSingleNode("xml").SelectSingleNode("MsgType").InnerText;  
  53.          if (wx.MsgType.Trim() == "text")  
  54.          {  
  55.              wx.Content = xml.SelectSingleNode("xml").SelectSingleNode("Content").InnerText;  
  56.          }  
  57.          if (wx.MsgType.Trim() == "event")  
  58.          {  
  59.              wx.EventName = xml.SelectSingleNode("xml").SelectSingleNode("Event").InnerText;  
  60.              wx.EventKey = xml.SelectSingleNode("xml").SelectSingleNode("EventKey").InnerText;  
  61.          }  
  62.          if (wx.MsgType.Trim() == "voice")  
  63.          {  
  64.              wx.Recognition = xml.SelectSingleNode("xml").SelectSingleNode("Recognition").InnerText;  
  65.          }  
  66.            
  67.          return wx;  
  68.      }  
  69.   
  70.   
  71.   
  72.   
  73. /// <summary>    
  74.      /// 发送文字消息    
  75.      /// </summary>    
  76.      /// <param name="wx">获取的收发者信息</param>    
  77.      /// <param name="content">内容</param>    
  78.      /// <returns></returns>    
  79.      private string sendTextMessage(wxmessage wx, string content)  
  80.      {  
  81.          string res = string.Format(@"<xml>  
  82.                                    <ToUserName><![CDATA[{0}]]></ToUserName>  
  83.                                    <FromUserName><![CDATA[{1}]]></FromUserName>  
  84.                                     <CreateTime>{2}</CreateTime>  
  85.                                     <MsgType><![CDATA[text]]></MsgType>  
  86.                                     <Content><![CDATA[{3}]]></Content>  
  87.                                    </xml> ",  
  88.              wx.FromUserName, wx.ToUserName, DateTime.Now, content);  
  89.          return res;  
  90.      }  
这样就可以相应你的菜单事件了,我上面的代码写的有很多可以优化的地方,这里主要以简介为主,以后我们会逐渐搭建起一个微信公共平台的.net框架,什么菜单类,消息类等等。
更多0




之前我们讲过让微信发送给我们普通的文本信息,下面我们来看看如何发送图文信息,需要注意的是这里说的是,让微信发给我们,而不是我们拍个图片发给微信处理,我们上传图片在以后的章节介绍.下面是发送图文消息的函数,涉及title(标题),description(摘要),picurl(图片),链接(url)几个关键的参数:

[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. protected string sendPicTextMessage(Msg _mode,string title,string description,string picurl,string url)  
  2.     {  
  3.          
  4.         string res = string.Format(@"<xml>  
  5.                                             <ToUserName><![CDATA[{0}]]></ToUserName>  
  6.                                             <FromUserName><![CDATA[{1}]]></FromUserName>  
  7.                                             <CreateTime>{2}</CreateTime>  
  8.                                             <MsgType><![CDATA[news]]></MsgType>  
  9.                                             <ArticleCount>1</ArticleCount>  
  10.                                             <Articles>  
  11.                                             <item>  
  12.                                             <Title><![CDATA[{3}]]></Title>   
  13.                                             <Description><![CDATA[{4}]]></Description>  
  14.                                             <PicUrl><![CDATA[{5}]]></PicUrl>  
  15.                                             <Url><![CDATA[{6}]]></Url>  
  16.                                             </item>  
  17.                                             </Articles>  
  18.                                    </xml> ",  
  19.            _mode.FromUserName, _mode.ToUserName, DateTime.Now,title, description, picurl, url);  
  20.   
  21.         return res;  
  22.   
  23.      }  

直接在调用函数即可:
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. protected void Page_Load(object sender, EventArgs e)  
  2.      {  
  3.           
  4.          MyMenu();  
  5.          wxmessage wx = GetWxMessage();  
  6.          string res = "";  
  7.   
  8.          if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.Trim() == "subscribe")  
  9.          {  
  10.              string content = "";  
  11.              content = "/:rose欢迎北京永杰友信科技有限公司/:rose\n直接回复“你好”";  
  12.              res = sendTextMessage(wx, content);  
  13.          }  
  14.          else if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.Trim() == "CLICK")  
  15.          {  
  16.              if(wx.EventKey=="Hello")  
  17.                  res = sendTextMessage(wx, "你好,欢迎使用北京永杰友信科技有限公司公共微信平台!");  
  18.              if(wx.EventKey=="P1")  
  19.                  res = sendTextMessage(wx, "你好,点击了产品1");  
  20.              if(wx.EventKey=="P2")  
  21.                  res = sendTextMessage(wx, "你好,点击了产品2");  
  22.          }  
  23.          else  
  24.          {  
  25.              if (wx.MsgType == "text" && wx.Content == "你好")  
  26.              {  
  27.                  res = sendTextMessage(wx, "你好,欢迎使用北京永杰友信科技有限公司公共微信平台!");  
  28.              }  
  29.              if (wx.MsgType == "text" && wx.Content == "图文")  
  30.              {  
  31.                  res = sendPicTextMessage(wx,"这里是一个标题","这里是摘要","http://mp.weixin.qq.com/wiki/skins/common/images/weixin_wiki_logo.png","http://www.4ugood.net");  
  32.              }  
  33.              else if (wx.MsgType == "voice")  
  34.              {  
  35.                  res = sendTextMessage(wx, wx.Recognition);  
  36.              }  
  37.              else  
  38.              {  
  39.                  res = sendTextMessage(wx, "你好,未能识别消息!");  
  40.              }  
  41.          }  
  42.   
  43.          Response.Write(res);  
  44.      }  
  45.   
  46.   
  47.   
  48.      private wxmessage GetWxMessage()  
  49.      {  
  50.          wxmessage wx = new wxmessage();  
  51.          StreamReader str = new StreamReader(Request.InputStream, System.Text.Encoding.UTF8);  
  52.          XmlDocument xml = new XmlDocument();  
  53.          xml.Load(str);  
  54.          wx.ToUserName = xml.SelectSingleNode("xml").SelectSingleNode("ToUserName").InnerText;  
  55.          wx.FromUserName = xml.SelectSingleNode("xml").SelectSingleNode("FromUserName").InnerText;  
  56.          wx.MsgType = xml.SelectSingleNode("xml").SelectSingleNode("MsgType").InnerText;  
  57.          if (wx.MsgType.Trim() == "text")  
  58.          {  
  59.              wx.Content = xml.SelectSingleNode("xml").SelectSingleNode("Content").InnerText;  
  60.          }  
  61.          if (wx.MsgType.Trim() == "event")  
  62.          {  
  63.              wx.EventName = xml.SelectSingleNode("xml").SelectSingleNode("Event").InnerText;  
  64.              wx.EventKey = xml.SelectSingleNode("xml").SelectSingleNode("EventKey").InnerText;  
  65.          }  
  66.          if (wx.MsgType.Trim() == "voice")  
  67.          {  
  68.              wx.Recognition = xml.SelectSingleNode("xml").SelectSingleNode("Recognition").InnerText;  
  69.          }  
  70.            
  71.          return wx;  
  72.      }  


更多0

举个例子,有人对着我们的公共微信号拍个照片发送过来,然后我们处理这个照片,比如进行ocr识别字(随后就会降到这个例子),或者人脸识别,或者拍照取证等,这些功能都是相当有用的。那么我们现在就要分析一下这个过程。微信平台肯定不能帮助我们OCR或者人脸识别等功能,要做这些功能首先到得到图片!用户拍摄的照片首先被上传到了wenxin的服务器,然后就有了一个mediaID,我们用这个mediaID可以下载到我们自己的服务器上然后处理,把结果给微信平台,由微信平台最终反馈给用户(关注者)。微信的开发文档已经给出了下载资源的办法,我改造为.net的,如下:

[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /// <summary>  
  2.     /// 下载保存多媒体文件,返回多媒体保存路径  
  3.     /// </summary>  
  4.     /// <param name="ACCESS_TOKEN"></param>  
  5.     /// <param name="MEDIA_ID"></param>  
  6.     /// <returns></returns>  
  7.     public string GetMultimedia(string ACCESS_TOKEN, string MEDIA_ID)  
  8.     {  
  9.         string file = string.Empty;  
  10.         string content = string.Empty;  
  11.         string strpath = string.Empty;  
  12.         string savepath = string.Empty;  
  13.         string stUrl = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=" + ACCESS_TOKEN + "&media_id=" + MEDIA_ID;  
  14.   
  15.         HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(stUrl);  
  16.   
  17.         req.Method = "GET";  
  18.         using (WebResponse wr = req.GetResponse())  
  19.         {  
  20.             HttpWebResponse myResponse = (HttpWebResponse)req.GetResponse();  
  21.   
  22.             strpath = myResponse.ResponseUri.ToString();  
  23.             WriteLog("接收类别://" + myResponse.ContentType);  
  24.             WebClient mywebclient = new WebClient();  
  25.             savepath = Server.MapPath("image") + "\\" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next().ToString().Substring(0, 4) + ".jpg";  
  26.             WriteLog("路径://" + savepath);  
  27.             try  
  28.             {  
  29.                 mywebclient.DownloadFile(strpath, savepath);  
  30.                 file = savepath;  
  31.             }  
  32.             catch (Exception ex)  
  33.             {  
  34.                 savepath = ex.ToString();  
  35.             }  
  36.   
  37.         }  
  38.         return file;  
  39.     }  

上面的两个参数很好理解,第一就是ACCESS_TOKEN,之前说过很多了,第二就是在微信服务器上的资源id,即mediaID。如果我们要下载微信服务器上的资源总要知道id吧。但是MEDIA_ID又是怎么产生的呢?我首先改造一下之前的消息实体类,加入MediaId 属性
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class wxmessage    
  2.   {    
  3.       public string FromUserName { getset; }    
  4.       public string ToUserName { getset; }    
  5.        public string MsgType { getset; }    
  6.        public string EventName { getset; }    
  7.        public string Content { getset; }  
  8.        public string Recognition { getset; }  
  9.        public string MediaId { getset; }  
  10.        public string EventKey { getset; }   
  11.    }  
然后改造一下GetWxMessage(),给MediaId赋值。
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private wxmessage GetWxMessage()  
  2.      {  
  3.          wxmessage wx = new wxmessage();  
  4.          StreamReader str = new StreamReader(Request.InputStream, System.Text.Encoding.UTF8);  
  5.          XmlDocument xml = new XmlDocument();  
  6.          xml.Load(str);  
  7.          wx.ToUserName = xml.SelectSingleNode("xml").SelectSingleNode("ToUserName").InnerText;  
  8.          wx.FromUserName = xml.SelectSingleNode("xml").SelectSingleNode("FromUserName").InnerText;  
  9.          wx.MsgType = xml.SelectSingleNode("xml").SelectSingleNode("MsgType").InnerText;  
  10.          if (wx.MsgType.Trim() == "text")  
  11.          {  
  12.              wx.Content = xml.SelectSingleNode("xml").SelectSingleNode("Content").InnerText;  
  13.          }  
  14.          if (wx.MsgType.Trim() == "event")  
  15.          {  
  16.              wx.EventName = xml.SelectSingleNode("xml").SelectSingleNode("Event").InnerText;  
  17.              wx.EventKey = xml.SelectSingleNode("xml").SelectSingleNode("EventKey").InnerText;  
  18.          }  
  19.          if (wx.MsgType.Trim() == "voice")  
  20.          {  
  21.              wx.Recognition = xml.SelectSingleNode("xml").SelectSingleNode("Recognition").InnerText;  
  22.          }  
  23.         if (wx.MsgType.Trim() == "image")  
  24.         {  
  25.             wx.MediaId = xml.SelectSingleNode("xml").SelectSingleNode("MediaId").InnerText;  
  26.         }  
  27.            
  28.          return wx;  
  29.      }  
如果我们在修改一下消息接受的代码,就可以做到,客户发一个照片给微信平台,程序检测到时图片,然后根据MediaId,调用GetMultimedia方法把图片下载到自己的服务器上。后面的工作嘛,你就想干什么干什么了。
刚才的例子好像是用户(关注者),发图片,然后通过微信平台到我们的服务器中,还有一种情况,用户发一个用户名:例如“hemeng”,然后我需要调用已经存在服务器中的hemeng头像的图片反馈给用户,这怎么办呢?如何把我们的图片传给微信平台,然后传给用户呢?我们就用到了上传得方法:
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /// <summary>  
  2.     /// 上传多媒体文件,返回 MediaId  
  3.     /// </summary>  
  4.     /// <param name="ACCESS_TOKEN"></param>  
  5.     /// <param name="Type"></param>  
  6.     /// <returns></returns>  
  7.     public string UploadMultimedia(string ACCESS_TOKEN, string Type)  
  8.     {  
  9.         string result = "";  
  10.         string wxurl = "http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token=" + ACCESS_TOKEN + "&type=" + Type;  
  11.         string filepath = Server.MapPath("image") + "\\hemeng80.jpg";(本地服务器的地址)  
  12.         WriteLog("上传路径:" + filepath);  
  13.         WebClient myWebClient = new WebClient();  
  14.         myWebClient.Credentials = CredentialCache.DefaultCredentials;  
  15.         try  
  16.         {  
  17.             byte[] responseArray = myWebClient.UploadFile(wxurl, "POST", filepath);  
  18.             result = System.Text.Encoding.Default.GetString(responseArray, 0, responseArray.Length);  
  19.             WriteLog("上传result:" + result);  
  20.             UploadMM _mode = JsonHelper.ParseFromJson<UploadMM>(result);  
  21.             result = _mode.media_id;  
  22.         }  
  23.         catch (Exception ex)  
  24.         {  
  25.             result = "Error:" + ex.Message;  
  26.         }  
  27.         WriteLog("上传MediaId:" + result);  
  28.         return result;  
  29.     }  
第二个参数如果是图片"image",可以参照微信的文档。函数的返回值就是一个MediaId,这样你就可以利用发送图片的函数,发给客户了,发送图片的函数如下:
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. protected string sendPicTextMessage(Msg _mode, string MediaId)  
  2.     {  
  3.         string res = string.Format(@"<xml>  
  4.                                             <ToUserName><![CDATA[{0}]]></ToUserName>  
  5.                                             <FromUserName><![CDATA[{1}]]></FromUserName>  
  6.                                             <CreateTime>{2}</CreateTime>  
  7.                                             <MsgType><![CDATA[image]]></MsgType>  
  8.                                             <Image>  
  9.                                             <MediaId><![CDATA[{3}]]></MediaId>  
  10.                                             </Image>  
  11.                                    </xml> ",  
  12.            _mode.FromUserName, _mode.ToUserName, DateTime.Now, MediaId);  
  13.   
  14.         return res;  
  15.     }  
其他视频,语音的操作也类似,就不再冗余介绍了。有了这些知识我们是不是能做不少应用了?当然是肯定的,但是我们的代码还不够优化,结构也不合理,不着急,我们会逐渐介绍到的,因为我们还没有完全了解完微信的强大功能。

更多0
今天我们来共同学习一下微信公共服务平台中一个重要内容---二维码扫描。众所周知二维码目前应用范围很广,在这里不再叙述背景了,但是值得一提的是目前大家手机上面应用的二维码扫描工具是支持的都是QR码和PDF417码标准,这就是为什么你用各种扫码工具扫出来的都一样的原因,因为大家都使用了同样的标准。

    在微信中的“扫一扫”功能也支持了这种标准,但是我们如果在微信公共服务平台中开发,使用的就不是这种标准了,而是微信自己的标准。也就是说如果你用通用软件生成的二维码“微信”,“我查查”等都可以扫描出来,但是你用微信公共服务平台中生成的二维码,就“只能用微信的扫一扫进行扫描”,别的软件扫描出来的结果均是微信自己加密的连接。这一点真的可以看出腾讯的野心了,不过话说回来了,你用人家的微信平台,肯定必须用人家的微信的扫一扫了。

    只是有一点,如果我们把生成好的二维码贴出来,让用户扫的时候必须都要加上一句“请使用微信的扫一扫进行扫描”,也就是说用户要想扫你的二维码就必须用微信软件,自己就必须用微信号!好阴险啊!!

    下面说一说我理解的微信二维码使用的过程,首先我们可以把自己想放在二维码里面的信息,使用自己的微信公共号生成这个二维码,通过web或者什么以图片的形式输出出来,然后我们对这这个二维码用微信的“扫一扫”扫描,如果你还未关注这个微信公共号,微信会提醒你关注,并反馈相应的信息,如果你关注了这个号,那么会自动反馈给你二维码里面的内容。

    下面开始代码的内容:
    首先我们参考微信的教程,使用自己的微信公共号生成一个二维码,并通过web显示出来。利用我们之前讲过的Access_Token创建一个含有自己信息的Ticket,自己的信息在这里叫做“scene_id”。微信平台使用了这样Json对象来描述Ticket:

临时二维码:
{"expire_seconds": 1800, "action_name": "QR_SCENE", "action_info": {"scene": {"scene_id": 123}}}
第一个参数代表有效时间,第二个参数就是临时二维码的标识,是一个常量,第三个参数就是我们要放进去的“scene_id”

永久二维码:
{"action_name": "QR_LIMIT_SCENE", "action_info": {"scene": {"scene_id": 123}}}
只是缺少了有效时间,其他不再解释了


看看下面创建Ticket的代码,函数返回值是包含了我们自定义信息的Ticket:

[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /// <summary>  
  2.     /// 创建二维码ticket  
  3.     /// </summary>  
  4.     /// <returns></returns>  
  5.     public static string CreateTicket(string TOKEN)  
  6.     {  
  7.   
  8.         string result = "";  
  9.         //string strJson = @"{""expire_seconds"":1800, ""action_name"": ""QR_SCENE"", ""action_info"": {""scene"": {""scene_id"":100000023}}}";  
  10.         string strJson = @"{""action_name"": ""QR_LIMIT_SCENE"", ""action_info"": {""scene"": {""scene_id"":100000024}}}";  
  11.         string wxurl = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + TOKEN;  
  12.   
  13.         WebClient myWebClient = new WebClient();  
  14.         myWebClient.Credentials = CredentialCache.DefaultCredentials;  
  15.         try  
  16.         {  
  17.   
  18.             result = myWebClient.UploadString(wxurl, "POST", strJson);  
  19.             //WriteLog("上传result:" + result);  
  20.             Ticket _mode = JsonHelper.ParseFromJson<Ticket>(result);  
  21.             //UploadMM _mode = JsonHelper.ParseFromJson<UploadMM>(result);  
  22.             //result = _mode.ticket;  
  23.             result = _mode.ticket + "_" + _mode.expire_seconds;  
  24.         }  
  25.         catch (Exception ex)  
  26.         {  
  27.             result = "Error:" + ex.Message;  
  28.         }  
  29.         //WriteLog("上传MediaId:" + result);  
  30.   
  31.         return result;  
  32.     }  
创建了Ticket以后,我们再根据这个Ticket创建一个图片,并保存在服务器上,函数返回的是图片在服务器上的路径(便于我们使用image控件显示出来):
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public string GetTicketImage(string TICKET)  
  2.     {  
  3.         string content = string.Empty;  
  4.         string strpath = string.Empty;  
  5.         string savepath = string.Empty;  
  6.   
  7.         string stUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + Server.UrlEncode(TICKET);  
  8.   
  9.         HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(stUrl);  
  10.   
  11.         req.Method = "GET";  
  12.   
  13.         using (WebResponse wr = req.GetResponse())  
  14.         {  
  15.             HttpWebResponse myResponse = (HttpWebResponse)req.GetResponse();  
  16.             strpath = myResponse.ResponseUri.ToString();  
  17.   
  18.             WebClient mywebclient = new WebClient();  
  19.   
  20.             savepath = Server.MapPath("image") + "\\" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next().ToString().Substring(0, 4) + "." + myResponse.ContentType.Split('/')[1].ToString();  
  21.   
  22.             try  
  23.             {  
  24.                 mywebclient.DownloadFile(strpath, savepath);  
  25.             }  
  26.             catch (Exception ex)  
  27.             {  
  28.                 savepath = ex.ToString();  
  29.             }  
  30.   
  31.   
  32.         }  
  33.         return strpath.ToString();  
  34.     }  
然后我们把这个图片显示出来就可以了:
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. protected void Page_Load(object sender, EventArgs e)  
  2.     {  
  3.         string _access_token = string.Empty;  
  4.         _access_token = IsExistAccess_Token();  
  5.   
  6.         string str = CreateTicket(_access_token);  
  7.         Response.Write(str + "<br/>");  
  8.         str = str.Split('_')[0].ToString();  
  9.         str = GetTicketImage(str);  
  10.         Image1.ImageUrl = str;  
  11.         Response.Write(str);  
  12.     }  
上面用到了一个Ticket类,我把代码也粘贴出来:
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /// <summary>  
  2. ///Ticket 的摘要说明  
  3. /// </summary>  
  4. public class Ticket  
  5. {  
  6.     public Ticket()  
  7.     {  
  8.         //  
  9.         //TODO: 在此处添加构造函数逻辑  
  10.         //  
  11.     }  
  12.   
  13.     string _ticket;  
  14.     string _expire_seconds;  
  15.   
  16.     /// <summary>  
  17.     /// 获取的二维码ticket,凭借此ticket可以在有效时间内换取二维码。  
  18.     /// </summary>  
  19.     public string ticket  
  20.     {  
  21.         get { return _ticket; }  
  22.         set { _ticket = value; }  
  23.     }  
  24.   
  25.     /// <summary>  
  26.     /// 凭证有效时间,单位:秒  
  27.     /// </summary>  
  28.     public string expire_seconds  
  29.     {  
  30.         get { return _expire_seconds; }  
  31.         set { _expire_seconds = value; }  
  32.     }  
  33. }  
第一部的工作我们做完了,按照微信自己的标准生成了一个包含我们自定义信息的二维码了,下面就是扫码过程了,这里您可以使用其他标准的扫码工具扫一下试试,我们包含的“scene_id”信息是扫不出来的,刚才说过了,这不是一个标准的二维码标准,是微信自己的!下面我们来写一下微信扫码的事件响应就OK了,这里有两个事件:第一是我们没有关注这个微信号时直接扫(扫完会提醒您关注),第二是我们已经关注后扫,我们把之前的代码加上这两个事件,不再解释了:
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. protected void Page_Load(object sender, EventArgs e)  
  2.      {  
  3. wxmessage wx = GetWxMessage();  
  4.          string res = "";  
  5.   
  6.   
  7.          if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.Trim() == "subscribe")  
  8.          {  
  9.              string content = "";  
  10.              if (!wx.EventKey.Contains("qrscene_"))  
  11.              {  
  12.                  content = "/:rose欢迎北京永杰友信科技有限公司/:rose\n直接回复“你好”";  
  13.                  res = sendTextMessage(wx, content);  
  14.              }  
  15.              else  
  16.              {  
  17.                  content = "二维码参数:\n" + wx.EventKey.Replace("qrscene_""");  
  18.                  res = sendTextMessage(wx, content);  
  19.              }  
  20.          }  
  21.   
  22.          else if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.ToLower() == "scan")  
  23.          {  
  24.              string str = "二维码参数:\n" + wx.EventKey;  
  25.              res = sendTextMessage(wx, str);  
  26.          }  
  27.          else if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.Trim() == "CLICK")  
  28.          {  
  29.              if(wx.EventKey=="HELLO")  
  30.                  res = sendTextMessage(wx, "你好,欢迎使用北京永杰友信科技有限公司公共微信平台!");  
  31.          }  
  32.          else  
  33.          {  
  34.              if (wx.MsgType == "text" && wx.Content == "你好")  
  35.              {  
  36.                  res = sendTextMessage(wx, "你好,欢迎使用北京永杰友信科技有限公司公共微信平台!");  
  37.              }  
  38.              else if (wx.MsgType == "voice")  
  39.              {  
  40.                  res = sendTextMessage(wx, wx.Recognition);  
  41.              }  
  42.              else  
  43.              {  
  44.                  res = sendTextMessage(wx, "你好,未能识别消息!");  
  45.              }  
  46.          }  
  47.   
  48.          Response.Write(res);  
  49.      }  
    OK,这样我们就完成了上面所设想的功能,扫码后先判断了是否关注,没有关注的提示关注,然后反馈我们自定义的参数“scene_id”,如果关注了同样直接反馈“scene_id”信息。

    这种应用很广的,我现在能想象到的有以下几个场景:
1、餐馆/商店
    我们把每道菜都用一个二维码进行标注,客人在点餐的时候使用微信的扫一扫功能进行点餐,第一次扫就提示客人请关注我们餐馆的微信号,并点了第一个菜,然后第二道。。这样我们就能很轻松的做到两件事情,第一,他关注了我们的微信号(为了留住回头客),第二,我们知道他喜欢吃什么口味,如喜欢川菜还是粤菜(为了给回头客更好的推荐)

2、调查表
    虽然大家都关注的是同一个微信号,但是不同的二维码有不同的意义,大家在扫码的过程中会有不同的需求,比如说我们准备3个二维码分别对应不同的表格给老中青三种客户,用户在扫码的同时就可以进入表格进行填写,如果在二维码中加入调查员的信息,我们还能对调查员进行绩效考核。

3、产品溯源
    同样的道理,没种产品或者不同的批次不同的地区都可以用不同的二维码进行编码,返回不同的信息,同时用户在扫码的同时又关注了我们的微信号。

4、扫码支付
    利用临时的二维码,每一笔交易,不同的帐户,不同的金额,生成不同的码,用户拍完以后进入不同的“微支付”。
    用途很多很多,不过还是那个前提-----“只能用微信扫!”
    先就说这么多吧,等我把这些最基础的技术开发写完,我们在来共同探讨和开发几个成品案例。

更多0
微信公共平台中涉及到地理位置的有两种情况:
       第一、我发送一个自选的地理位置给微信,然后微信可以自动反馈响应的信息。
       第二、让微信获取我们GPS定位地址位置,反馈响应的信息。

       首先我们先来看第一种,在微信中除了可以发文本,图片,语音等还有一个信息就是地理位置,按照微信接受地理信息的XML信息,我们需要改造一下之前的wxmessage类加上几个属性:

[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class wxmessage    
  2.    {    
  3.        public string FromUserName { getset; }    
  4.        public string ToUserName { getset; }    
  5.         public string MsgType { getset; }    
  6.         public string EventName { getset; }    
  7.         public string Content { getset; }  
  8.         public string Recognition { getset; }  
  9.         public string MediaId { getset; }  
  10.         public string EventKey { getset; }   
  11.         public string Location_X { getset; }  
  12.         public string Location_Y { getset; }  
  13.         public string Scale { getset; }  
  14.         public string Label { getset; }  
  15.   
  16.     }  
       其中Location_X代表纬度,Location_Y代表经度,Scale代表缩放比例,Label代表位置的描述
       和接受文本,语音消息一下样,地理信息的MsgType为“location”,修改一下之前的GetWxMessage()函数和OnLoad里面的消息处理:
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private wxmessage GetWxMessage()  
  2.      {  
  3.          wxmessage wx = new wxmessage();  
  4.          StreamReader str = new StreamReader(Request.InputStream, System.Text.Encoding.UTF8);  
  5.          XmlDocument xml = new XmlDocument();  
  6.          xml.Load(str);  
  7.          wx.ToUserName = xml.SelectSingleNode("xml").SelectSingleNode("ToUserName").InnerText;  
  8.          wx.FromUserName = xml.SelectSingleNode("xml").SelectSingleNode("FromUserName").InnerText;  
  9.          wx.MsgType = xml.SelectSingleNode("xml").SelectSingleNode("MsgType").InnerText;  
  10.          if (wx.MsgType.Trim() == "text")  
  11.          {  
  12.              wx.Content = xml.SelectSingleNode("xml").SelectSingleNode("Content").InnerText;  
  13.          }  
  14.          if (wx.MsgType.Trim() == "location")  
  15.          {  
  16.              wx.Location_X = xml.SelectSingleNode("xml").SelectSingleNode("Location_X").InnerText;  
  17.              wx.Location_Y = xml.SelectSingleNode("xml").SelectSingleNode("Location_Y").InnerText;  
  18.              wx.Scale = xml.SelectSingleNode("xml").SelectSingleNode("Scale").InnerText;  
  19.              wx.Label = xml.SelectSingleNode("xml").SelectSingleNode("Label").InnerText;  
  20.   
  21.          }  
  22.          if (wx.MsgType.Trim() == "event")  
  23.          {  
  24.              wx.EventName = xml.SelectSingleNode("xml").SelectSingleNode("Event").InnerText;  
  25.              wx.EventKey = xml.SelectSingleNode("xml").SelectSingleNode("EventKey").InnerText;  
  26.          }  
  27.          if (wx.MsgType.Trim() == "voice")  
  28.          {  
  29.              wx.Recognition = xml.SelectSingleNode("xml").SelectSingleNode("Recognition").InnerText;  
  30.          }  
  31.            
  32.          return wx;  
  33.      }  
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. protected void Page_Load(object sender, EventArgs e)  
  2.   {  
  3.       wxmessage wx = GetWxMessage();  
  4.       string res = "";  
  5.   
  6.   
  7.       if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.Trim() == "subscribe")  
  8.       {  
  9.           string content = "";  
  10.           if (!wx.EventKey.Contains("qrscene_"))  
  11.           {  
  12.               content = "/:rose欢迎北京永杰友信科技有限公司/:rose\n直接回复“你好”";  
  13.               res = sendTextMessage(wx, content);  
  14.           }  
  15.           else  
  16.           {  
  17.               content = "二维码参数:\n" + wx.EventKey.Replace("qrscene_""");  
  18.               res = sendTextMessage(wx, content);  
  19.           }  
  20.       }  
  21.   
  22.       else if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.ToLower() == "scan")  
  23.       {  
  24.           string str = "二维码参数:\n" + wx.EventKey;  
  25.           res = sendTextMessage(wx, str);  
  26.       }  
  27.       else if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.Trim() == "CLICK")  
  28.       {  
  29.           if(wx.EventKey=="HELLO")  
  30.               res = sendTextMessage(wx, "你好,欢迎使用北京永杰友信科技有限公司公共微信平台!");  
  31.       }  
  32.       else  
  33.       {  
  34.           WriteLog(wx.MsgType);  
  35.           if (wx.MsgType == "text" && wx.Content == "你好")  
  36.           {  
  37.               res = sendTextMessage(wx, "你好,欢迎使用北京永杰友信科技有限公司公共微信平台!");  
  38.           }  
  39.           else if (wx.MsgType == "voice")  
  40.           {  
  41.               res = sendTextMessage(wx, wx.Recognition);  
  42.           }  
  43.           else if (wx.MsgType == "location")  
  44.           {  
  45.               res = sendTextMessage(wx, "您发送的位置是:" + wx.Label + ";纬度是:" + wx.Location_X + ";经度是:" + wx.Location_Y + ";缩放比例为:" + wx.Scale);  
  46.           }  
  47.           else  
  48.           {  
  49.               res = sendTextMessage(wx, "你好,未能识别消息!");  
  50.           }  
  51.       }  
  52.   
  53.       Response.Write(res);  
  54.   }  
       这样当我们发送一个地理位置信息的时候就可以反馈响应的信息了。值得一提的是:这里的地理信息位置无需授权,因为自己发送的地理信息位置不一定是自己的真实位置,我们可以在输入界面进行任意选择,不会涉及隐私。
       当然如果我们像制作类似于“我附近”的功能的时候,就必须有两个条件,在微信公共号中开启获取用户地理信息的功能。第二,用户自己在关注微信的时候允许微信公共号获取我的位置。这就需要用到我们在文章开始的时候给大家介绍的第二种情况了。按照微信的解释,当一个会话开始的时候(也就是说进入对话界面的时候),首先获取一下,然后每个五秒自动获取一次。也就是就是说获得用户位置信息的时候触发的不是“你一言我一语的对话”,而是一个特殊的事件,每格五秒出发一次。这里被定义为MsgType为“event”,而为了区别于其他的“event”,他的EventName(其实官方叫做event)为“LOCATION”(大写哦)。
       下面我依然需要按照微信的格式修改我们的wxmessage类:
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class wxmessage    
  2.   {    
  3.       public string FromUserName { getset; }    
  4.       public string ToUserName { getset; }    
  5.        public string MsgType { getset; }    
  6.        public string EventName { getset; }    
  7.        public string Content { getset; }  
  8.        public string Recognition { getset; }  
  9.        public string MediaId { getset; }  
  10.        public string EventKey { getset; }   
  11.        public string Location_X { getset; }  
  12.        public string Location_Y { getset; }  
  13.        public string Scale { getset; }  
  14.        public string Label { getset; }  
  15.        public string Latitude { getset; }  
  16.        public string Longitude { getset; }  
  17.        public string Precision { getset; }  
  18.   
  19.    }  
       改造一下GetWxMessage()函数和OnLoad函数:
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private wxmessage GetWxMessage()  
  2.      {  
  3.          wxmessage wx = new wxmessage();  
  4.          StreamReader str = new StreamReader(Request.InputStream, System.Text.Encoding.UTF8);  
  5.          XmlDocument xml = new XmlDocument();  
  6.          xml.Load(str);  
  7.          wx.ToUserName = xml.SelectSingleNode("xml").SelectSingleNode("ToUserName").InnerText;  
  8.          wx.FromUserName = xml.SelectSingleNode("xml").SelectSingleNode("FromUserName").InnerText;  
  9.          wx.MsgType = xml.SelectSingleNode("xml").SelectSingleNode("MsgType").InnerText;  
  10.          WriteLog("MsgType:"+wx.MsgType);  
  11.          if (wx.MsgType.Trim() == "event")  
  12.          {  
  13.              wx.EventName = xml.SelectSingleNode("xml").SelectSingleNode("Event").InnerText;  
  14.              WriteLog(wx.EventName);  
  15.              if (wx.EventName.ToUpper() == "LOCATION")  
  16.              {  
  17.                  wx.Latitude = xml.SelectSingleNode("xml").SelectSingleNode("Latitude").InnerText;  
  18.                  wx.Longitude = xml.SelectSingleNode("xml").SelectSingleNode("Longitude").InnerText;  
  19.                  wx.Precision = xml.SelectSingleNode("xml").SelectSingleNode("Precision").InnerText;  
  20.              }  
  21.              else  
  22.              {  
  23.                  wx.EventKey = xml.SelectSingleNode("xml").SelectSingleNode("EventKey").InnerText;  
  24.              }  
  25.          }  
  26.          if (wx.MsgType.Trim() == "text")  
  27.          {  
  28.              wx.Content = xml.SelectSingleNode("xml").SelectSingleNode("Content").InnerText;  
  29.          }  
  30.          if (wx.MsgType.Trim() == "location")  
  31.          {  
  32.              wx.Location_X = xml.SelectSingleNode("xml").SelectSingleNode("Location_X").InnerText;  
  33.              wx.Location_Y = xml.SelectSingleNode("xml").SelectSingleNode("Location_Y").InnerText;  
  34.              wx.Scale = xml.SelectSingleNode("xml").SelectSingleNode("Scale").InnerText;  
  35.              wx.Label = xml.SelectSingleNode("xml").SelectSingleNode("Label").InnerText;  
  36.   
  37.          }  
  38.            
  39.          if (wx.MsgType.Trim() == "voice")  
  40.          {  
  41.              wx.Recognition = xml.SelectSingleNode("xml").SelectSingleNode("Recognition").InnerText;  
  42.          }  
  43.            
  44.          return wx;  
  45.      }  
       当MsgType为event的时候我们之前用到的是菜单的事件,现在我们需要加入其EventName为"LOCATION"的代码段,因为现在还没有涉及其他的event我后面就用else好了,后面我会把代码写的规范些。在这里分别给新增的三个属性赋值,然后修改一下Onload函数
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. protected void Page_Load(object sender, EventArgs e)  
  2.     {  
  3.   
  4.         wxmessage wx = GetWxMessage();  
  5.         string res = "";  
  6.   
  7.   
  8.         if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.Trim() == "subscribe")  
  9.         {  
  10.             string content = "";  
  11.             if (!wx.EventKey.Contains("qrscene_"))  
  12.             {  
  13.                 content = "/:rose欢迎北京永杰友信科技有限公司/:rose\n直接回复“你好”";  
  14.                 res = sendTextMessage(wx, content);  
  15.             }  
  16.             else  
  17.             {  
  18.                 content = "二维码参数:\n" + wx.EventKey.Replace("qrscene_""");  
  19.                 res = sendTextMessage(wx, content);  
  20.             }  
  21.         }  
  22.   
  23.         else if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.ToLower() == "scan")  
  24.         {  
  25.             string str = "二维码参数:\n" + wx.EventKey;  
  26.             res = sendTextMessage(wx, str);  
  27.         }  
  28.         else if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.Trim() == "CLICK")  
  29.         {  
  30.             if(wx.EventKey=="HELLO")  
  31.                 res = sendTextMessage(wx, "你好,欢迎使用北京永杰友信科技有限公司公共微信平台!");  
  32.         }  
  33.         else if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.Trim() == "LOCATION")  
  34.         {  
  35.             res = sendTextMessage(wx, "您的位置是经度:" + wx.Latitude + ",维度是:" + wx.Longitude+",地理经度为:"+wx.Precision);  
  36.         }  
  37.         else  
  38.         {  
  39.             if (wx.MsgType == "text" && wx.Content == "你好")  
  40.             {  
  41.                 res = sendTextMessage(wx, "你好,欢迎使用北京永杰友信科技有限公司公共微信平台!");  
  42.             }  
  43.             else if (wx.MsgType == "voice")  
  44.             {  
  45.                 res = sendTextMessage(wx, wx.Recognition);  
  46.             }  
  47.             else if (wx.MsgType == "location")  
  48.             {  
  49.                 res = sendTextMessage(wx, "您发送的位置是:" + wx.Label + ";纬度是:" + wx.Location_X + ";经度是:" + wx.Location_Y + ";缩放比例为:" + wx.Scale);  
  50.             }  
  51.             else  
  52.             {  
  53.                 res = sendTextMessage(wx, "你好,未能识别消息!");  
  54.             }  
  55.         }  
  56.   
  57.         Response.Write(res);  
  58.     }  
       好了,完成,这样当你开启你的微信“获得用户位置信息”的时候微信平台会提醒你,是仅进入会话第一次获取,还是每个5秒获取一次,如果你选择了后者,你就会看到,每5秒会反馈给你一个地理位置的信息。
       这里面需要非常注意的是:我按照这样认为没有问题了,但是怎么也获得不了信息,那是因为我在进入会话的时候,你会看到你的手机GPS在搜索,在GPS定位以前,是不会看到内容的。可以这样理解,当你GPS搜索定位后,才会触发获得用户位置信息的事件,这一点并不是我想象的通过基站定位也可以获得大致的位置,这一点需要开发者注意,我就是弄了半天,等我出门儿,手机定位了无意间看到了回复,这才恍然大悟。
       说到这里可以各位会问只知道经纬度坐标有什么用?又不是具体位置。其实不然,我们可以使用多种方法知道位置详细的信息,例如我们可以通过BaiduMap API的地址反向解析指导这个坐标在那个城市,那个街道等内容,甚至可以知道附近的情况,这里就不再多说了,以后有机会和大家一起来谈谈BaiduMap

更多0
这次我们来一起研究一下“客服消息”,首先明确一下“客服消息”的概念。这不同于之前的“被动响应消息”,也就是说并不是之前“你一言我一语的即时响应”,可能在某种情况下你需要给不同的人主动发送消息,例如你的餐馆推出了新的川菜,那么你需要给喜欢川菜的人发送消息,而并不是等着被人发送“有什么新菜”后,然后反馈给客户,我推出了什么什么的。


       说道这里可能有人会问,那不是群发吗?微信不是每天只能发一条吗?服务号每个月发一条吗?答案很明确微信说的是“客服消息”,也不是群发,它跟群发的区别就在于只要关注了我,那么我就可以群发给你消息,而为了不让用户感到讨厌,微信作了严格的群发条数限制。而“客服消息”则是只有关注你的人向你发送了消息,你才能主动推送。就像打电话只有人家问过你问题了,你才能回答,并且继续跟进回答。再举一个例子:你通过被人知道了我的手机号,存下来了,你突然给我打电话,我肯定是抵触的。但是如果我给你打过电话,你通过来电显示知道了我的号码,以后再给我打电话,说明我们是认识的,我最少不会抵触。这就使群发/被动响应/客服消息的本质区别。


       就像我们可以通过收集电话号码,手机自己的客户信息一样,一旦他们的信息被我们收录。那么我们就可以突破群发条数的限制了,按照微信的限制群发一个月只能一条(服务号),但是“客服消息”则可以一天50000条,足够用了。


       下面的问题就是如何手机客户的“手机号”了,微信里面有一个OPENID,这就使手机号了,这个是关注你的用户的唯一标识,这个标识是不会变的,但是同一个用户关注不同的微信号,那么他在不同微信号中的ID是不一样的。如何取得OPENID呢?


       网上找了些资料,有的说的的确是错误的,有的还说要通过OAuth 2.0授权才可以,这个的确可以,但是太复杂了吧,通过我的测试得出了这样的结论“只要用户和你的公共微信好发生交互”就可以取得他的OPENID了。就如同打电话一样,只要用户给你打了电话,你一定知道他的电话了。在微信里是这样的:用户只要发信息给你,或者点了某个菜单,发过来的信息都会有一个“FromUserName”,这个就使OPENID了。我们可以建立一个数据库来收集这些宝贵的用户身份信息,也就是记录他的“电话号码”,有了电话号码,我们就可以以后经常与客户主动打电话了。我做这样的一个实验:


       首先记录用户的OPENID在OnLoad函数第二行里面加上一个 WriteLog(wx.FromUserName);把它记录在一个文本文件中

[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. protected void Page_Load(object sender, EventArgs e)  
  2.      {  
  3.          wxmessage wx = GetWxMessage();  
  4.          WriteLog(wx.FromUserName);  
  5.          string res = "";  
  6.   
  7.   
  8.          if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.Trim() == "subscribe")  
  9.          {  
  10.              string content = "";  
  11.              if (!wx.EventKey.Contains("qrscene_"))  
  12.              {  
  13.                  content = "/:rose欢迎北京永杰友信科技有限公司/:rose\n直接回复“你好”";  
  14.                  res = sendTextMessage(wx, content);  
  15.              }  
  16.              else  
  17.              {  
  18.                  content = "二维码参数:\n" + wx.EventKey.Replace("qrscene_""");  
  19.                  res = sendTextMessage(wx, content);  
  20.              }  
  21.          }  
  22.   
  23.          else if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.ToLower() == "scan")  
  24.          {  
  25.              string str = "二维码参数:\n" + wx.EventKey;  
  26.              res = sendTextMessage(wx, str);  
  27.          }  
  28.          else if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.Trim() == "CLICK")  
  29.          {  
  30.              if(wx.EventKey=="HELLO")  
  31.                  res = sendTextMessage(wx, "你好,欢迎使用北京永杰友信科技有限公司公共微信平台!");  
  32.          }  
  33.          else if (!string.IsNullOrEmpty(wx.EventName) && wx.EventName.Trim() == "LOCATION")  
  34.          {  
  35.              res = sendTextMessage(wx, "您的位置是经度:" + wx.Latitude + ",维度是:" + wx.Longitude+",地理经度为:"+wx.Precision);  
  36.          }  
  37.          else  
  38.          {  
  39.              if (wx.MsgType == "text" && wx.Content == "你好")  
  40.              {  
  41.                   
  42.                  res = sendTextMessage(wx, "你好,欢迎使用北京永杰友信科技有限公司公共微信平台!");  
  43.              }  
  44.              else if (wx.MsgType == "voice")  
  45.              {  
  46.                  res = sendTextMessage(wx, wx.Recognition);  
  47.              }  
  48.              else if (wx.MsgType == "location")  
  49.              {  
  50.                  res = sendTextMessage(wx, "您发送的位置是:" + wx.Label + ";纬度是:" + wx.Location_X + ";经度是:" + wx.Location_Y + ";缩放比例为:" + wx.Scale);  
  51.              }  
  52.              else  
  53.              {  
  54.                  res = sendTextMessage(wx, "你好,未能识别消息!");  
  55.              }  
  56.          }  
  57.   
  58.          
  59.   
  60.          Response.Write(res);  
  61.      }  
WriteLog的方法是这样的:
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /// <summary>  
  2.     /// 写日志(用于跟踪)  
  3.     /// </summary>  
  4.     private void WriteLog(string strMemo)  
  5.     {  
  6.         string filename = Server.MapPath("/logs/log.txt");  
  7.         if (!Directory.Exists(Server.MapPath("//logs//")))  
  8.             Directory.CreateDirectory("//logs//");  
  9.         StreamWriter sr = null;  
  10.         try  
  11.         {  
  12.             if (!File.Exists(filename))  
  13.             {  
  14.                 sr = File.CreateText(filename);  
  15.             }  
  16.             else  
  17.             {  
  18.                 sr = File.AppendText(filename);  
  19.             }  
  20.             sr.WriteLine(strMemo);  
  21.         }  
  22.         catch  
  23.         {  
  24.   
  25.         }  
  26.         finally  
  27.         {  
  28.             if (sr != null)  
  29.                 sr.Close();  
  30.         }  
  31.     }  
        这样当客户发送任何一种信息给微信公共号,我们的log.txt文件中就会记录这个OPENID,我先打开Log.txt这个文件看看OPENID号,我的事这样的“oV93gjl5slD3p29yS1dOijy-pqZ8”,有了这个OPENID很多事情就都好办了,以后我们还会介绍如何获取客户的信息。这里先说“客户消息”吧。

        下面我们建立一个新的ASPX页面,在这个页面里面我就可以给这些用户发信息了。这个页面(SendMessage.aspx.cs)很简单就使两个文本框和一个按钮:

[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. string MyOpenID;  
  2. string MyContent;  
  3. protected void Page_Load(object sender, EventArgs e)  
  4. {  
  5.     MyOpenID = "oV93gjl5slD3p29yS1dOijy-pqZ8";  
  6.     MyContent = "这是一个客服消息";  
  7.     UserName.Text = MyOpenID;  
  8.     Content.Text = MyContent;  
  9. }  
  10. protected void Button1_Click(object sender, EventArgs e)  
  11. {  
  12.     string res = "";  
  13.     string Access_Token = IsExistAccess_Token();  
  14.      
  15.     string posturl = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + Access_Token;  
  16.     string postData = "{\"touser\":\"" + UserName.Text + "\",\"msgtype\":\"text\",\"text\":{\"content\":\"" + Content.Text + "\"}}";  
  17.     res = GetPage(posturl, postData);  
  18.       
  19.     Response.Write(res);  
  20. }  
       中间还用到了之前提到的3个函数:
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public string GetPage(string posturl, string postData)  
  2.    {  
  3.        Stream outstream = null;  
  4.        Stream instream = null;  
  5.        StreamReader sr = null;  
  6.        HttpWebResponse response = null;  
  7.        HttpWebRequest request = null;  
  8.        Encoding encoding = Encoding.UTF8;  
  9.        byte[] data = encoding.GetBytes(postData);  
  10.        // 准备请求...  
  11.        try  
  12.        {  
  13.            // 设置参数  
  14.            request = WebRequest.Create(posturl) as HttpWebRequest;  
  15.            CookieContainer cookieContainer = new CookieContainer();  
  16.            request.CookieContainer = cookieContainer;  
  17.            request.AllowAutoRedirect = true;  
  18.            request.Method = "POST";  
  19.            request.ContentType = "application/x-www-form-urlencoded";  
  20.            request.ContentLength = data.Length;  
  21.            outstream = request.GetRequestStream();  
  22.            outstream.Write(data, 0, data.Length);  
  23.            outstream.Close();  
  24.            //发送请求并获取相应回应数据  
  25.            response = request.GetResponse() as HttpWebResponse;  
  26.            //直到request.GetResponse()程序才开始向目标网页发送Post请求  
  27.            instream = response.GetResponseStream();  
  28.            sr = new StreamReader(instream, encoding);  
  29.            //返回结果网页(html)代码  
  30.            string content = sr.ReadToEnd();  
  31.            string err = string.Empty;  
  32.            return content;  
  33.        }  
  34.        catch (Exception ex)  
  35.        {  
  36.            string err = ex.Message;  
  37.            Response.Write(err);  
  38.            return string.Empty;  
  39.        }  
  40.    }  
  41.   
  42.    /// <summary>  
  43.    /// 根据当前日期 判断Access_Token 是否超期  如果超期返回新的Access_Token   否则返回之前的Access_Token  
  44.    /// </summary>  
  45.    /// <param name="datetime"></param>  
  46.    /// <returns></returns>  
  47.    public static string IsExistAccess_Token()  
  48.    {  
  49.   
  50.        string Token = string.Empty;  
  51.        DateTime YouXRQ;  
  52.        // 读取XML文件中的数据,并显示出来 ,注意文件路径  
  53.        string filepath = HttpContext.Current.Server.MapPath("XMLFile.xml");  
  54.   
  55.        StreamReader str = new StreamReader(filepath, System.Text.Encoding.UTF8);  
  56.        XmlDocument xml = new XmlDocument();  
  57.        xml.Load(str);  
  58.        str.Close();  
  59.        str.Dispose();  
  60.        Token = xml.SelectSingleNode("xml").SelectSingleNode("Access_Token").InnerText;  
  61.        YouXRQ = Convert.ToDateTime(xml.SelectSingleNode("xml").SelectSingleNode("Access_YouXRQ").InnerText);  
  62.   
  63.        if (DateTime.Now > YouXRQ)  
  64.        {  
  65.            DateTime _youxrq = DateTime.Now;  
  66.            Access_token mode = GetAccess_token();  
  67.            xml.SelectSingleNode("xml").SelectSingleNode("Access_Token").InnerText = mode.access_token;  
  68.            _youxrq = _youxrq.AddSeconds(int.Parse(mode.expires_in));  
  69.            xml.SelectSingleNode("xml").SelectSingleNode("Access_YouXRQ").InnerText = _youxrq.ToString();  
  70.            xml.Save(filepath);  
  71.            Token = mode.access_token;  
  72.        }  
  73.        return Token;  
  74.    }  
  75.   
  76.   
  77.   
  78.    public static Access_token GetAccess_token()  
  79.    {  
  80.        string appid = "wx043225275885dafd";  
  81.        string secret = "cb4425b24ab79ef875029cf0bf326ae9";  
  82.        string strUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret;  
  83.        Access_token mode = new Access_token();  
  84.   
  85.        HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(strUrl);  
  86.   
  87.        req.Method = "GET";  
  88.        using (WebResponse wr = req.GetResponse())  
  89.        {  
  90.            HttpWebResponse myResponse = (HttpWebResponse)req.GetResponse();  
  91.   
  92.            StreamReader reader = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8);  
  93.   
  94.            string content = reader.ReadToEnd();  
  95.            //Response.Write(content);  
  96.            //在这里对Access_token 赋值  
  97.            Access_token token = new Access_token();  
  98.            token = JsonHelper.ParseFromJson<Access_token>(content);  
  99.            mode.access_token = token.access_token;  
  100.            mode.expires_in = token.expires_in;  
  101.        }  
  102.        return mode;  
  103.    }  


        这个页面就是这些了,打开这个页面然后发送消息试试?很不错吧,这样在配合上我们的数据库啦,什么循环了,就可以突破了微信群发的限制,做到定项的群发消息推送了!这里面能发很多种消息:文本,语音,视频,图文,图片等等。只是Json而已,聪明的你一定可以举一反三的。


更多0

我们首先来认识一下OAuth协议吧,这个东西很早就听说过,总觉得离我很远(我的项目用不到这些),但是最近不得不学习一下了。我在网上找了一些解释,认为解释的最好的是这样说的(出处:http://hi.baidu.com/powerthinks/item/f1cb9b3c7a88251c9dc65efa)

     如果你开车去酒店赴宴,你经常会苦于找不到停车位而耽误很多时间。是否有好办法可以避免这个问题呢?有的,听说有一些豪车的车主就不担心这个问题。豪车一般配备两种钥匙:主钥匙和泊车钥匙。当你到酒店后,只需要将泊车钥匙交给服务生,停车的事情就由服务生去处理。与主钥匙相比,这种泊车钥匙的使用功能是受限制的:它只能启动发动机并让车行驶一段有限的距离,可以锁车,但无法打开后备箱,无法使用车内其他设备。这里就体现了一种简单的“开放授权”思想:通过一把泊车钥匙,车主便能将汽车的部分使用功能(如启动发动机、行驶一段有限的距离)授权给服务生。

    授权是一个古老的概念,它是一个多用户系统必须支持的功能特性。比如,Alice和Bob都是Google的用户,那么Alice应该可以将自己的照片授权给Bob访问。但请注意到,这种授权是一种封闭授权,它只支持系统内部用户之间的相互授权,而不能支持与其他外部系统或用户之间的授权。比如说,Alice想使用“网易印像服务”将她的部分照片冲印出来,她怎么能做到呢?

肯定有人会说,Alice可以将自己的Google用户名和密码告诉网易印像服务,事情不就解决了吗?是的,但只有毫不关注安全和隐私的同学才会出此“绝招”。那么我们就来想一想,这一“绝招”存在哪些问题?

(1) 网易印像服务可能会缓存Alice的用户名和密码,而且可能没有加密保护。它一旦遭到攻击,Alice就会躺着中枪。

(2) 网易印像服务可以访问Alice在Google上的所有资源,Alice无法对他们进行最小的权限控制,比如只允许访问某一张照片,1小时内访问有效。

(3) Alice无法撤消她的单个授权,除非Alice更新密码。

在以Web服务为核心的云计算时代,像用户Alice的这种授权需求变得日益迫切与兴盛,“开放授权(Open Authorization)”也正因此而生,意在帮助Alice将她的资源授权给第三方应用,支持细粒度的权限控制,并且不会泄漏Alice的密码或其它认证凭据。

  

上面的例子写的通俗易懂,各位一看就明白了,后面作者还附了一个这样图,以及注释:

 

从引言部分的描述我们可以看出,OAuth的参与实体至少有如下三个:

· RO (resourceowner): 资源所有者,对资源具有授权能力的人。如上文中的用户Alice。

· RS (resourceserver): 资源服务器,它存储资源,并处理对资源的访问请求。如Google资源服务器,它所保管的资源就是用户Alice的照片。

· Client: 第三方应用,它获得RO的授权后便可以去访问RO的资源。如网易印像服务。

此外,为了支持开放授权功能以及更好地描述开放授权协议,OAuth引入了第四个参与实体:

· AS(authorization server): 授权服务器,它认证RO的身份,为RO提供授权审批流程,并最终颁发授权令牌(Access Token)。读者请注意,为了便于协议的描述,这里只是在逻辑上把AS与RS区分开来;在物理上,AS与RS的功能可以由同一个服务器来提供服务。

 

如图1所示,协议的基本流程如下:

(1) Client请求RO的授权,请求中一般包含:要访问的资源路径,操作类型,Client的身份等信息。

(2) RO批准授权,并将“授权证据”发送给Client。至于RO如何批准,这个是协议之外的事情。典型的做法是,AS提供授权审批界面,让RO显式批准。这个可以参考下一节实例化分析中的描述。

(3) Client向AS请求“访问令牌(AccessToken)”。此时,Client需向AS提供RO的“授权证据”,以及Client自己身份的凭证。

(4) AS验证通过后,向Client返回“访问令牌”。访问令牌也有多种类型,若为bearer类型,那么谁持有访问令牌,谁就能访问资源。

(5) Client携带“访问令牌”访问RS上的资源。在令牌的有效期内,Client可以多次携带令牌去访问资源。

(6) RS验证令牌的有效性,比如是否伪造、是否越权、是否过期,验证通过后,才能提供服务。

 

虽然上面的例子举的很好,图画的也很清楚,可是对于我这种愚钝的人,还是理解了半天,请允许我在此狗尾续貂一次吧:

其实上面的图就如同这样一个故事

1、我的一个同事小张(Client),向我或者公司(RO)借钱,他会给我说:“借给我2000元,可以吗?”(也就是说向我请求一个有限的资源,就是Authorization Request);

2、这时我肯定不会把我的银行卡给他,并告诉他密码,我要用到OAuth。首先我会说“好的”,并且给他写一个条,上面写着“允许小张借款2000元”的请求(Authorization Grant);

3、小张拿着我写的条(AuthorizationGrant),给财务总监(AS);

4、财务总监看到我的条后会给小张一个提款单(Access Token),上面写着请出纳给小张支出2000元的借款。

5、小张拿到了提款单(AccessToken)到出纳那里,按照公司的规定,出纳只有看到了财务总监给的提款单(Access Token),才能过支出钱,这是出纳核对后,小张就顺利的拿到了2000元钱(Protected Resource)。

 

根据上面的故事我们来说已说OAuth的特点:

1、小张不可能知道,我或者公司总共有多少钱;

2、我也保护了账户的密码,维护的公司的制度;

3、就像现实中一样,财务总监和出纳一般都在一起办公,而AS和RS一般也会在同一个服务器上;

4、按照同样的公司制度(也就是OAuth),其他人不管谁来支出钱都要这样,我只需要保证制度执行的严密,其他任何人都不会知道我的帐务信息了。

这也就是OAuth全称--- OpenAuthorization(开放式授权)的意义了。

 

下面我来看看为微信中是如何实现这个过程的,我引用了方倍工作室教程里面的图(http://www.cnblogs.com/txw1958/p/weixin71-oauth20.html):

 

在这个途中User就是我例子中的小张,APP就是我,Auth_svr就是财务总监和出纳。

如果我使用微信中的官法提法因该这么说:

1、小张向我提出访问,访问过程涉及以下参数:


   也就是要知道我的APPID:其实就是我的名字;redirect_uri:到财务那里怎么走;response_type:知道我想我要批条(请填写code);scope批条的类别(后面会介绍到);state:到财务那里带些什么(参数)。

 

2、我同意了他的要求

  也就是微信帮助提到的“如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE。”也就是我给了小张一个批条(code),告诉小张去财务的路,以及到那里需要带些什么。

 

3、小张拿着我的批条到财务总监那里得到提款单

小张拿着我的批条(code),按照“redirect_uri/?code=CODE&state=STATE”这个路径去财务那里“通过code换取网页授权access_token”


上图可以知道我还可以获得OPENID!这个是非常重要的,前一章提到了它的用处,微信在这里还特别强调了“获取用户基本信息接口是在用户和公众号产生消息交互时,才能根据用户OpenID获取用户基本信息,而网页授权的方式获取用户基本信息,则无需消息交互,只是用户进入到公众号的网页,就可弹出请求用户授权的界面,用户授权后,就可获得其基本信息(此过程甚至不需要用户已经关注公众号。)”

 

4、小张拿到了提款单又到出纳那里提款

得到了access_token后,拉取用户信息,也就是“通过access_token和openid拉取用户信息了。”


最终得到是如下的信息:

 

本来就此已经说完了,不过不少研发人员可能还是会有疑问:“费这么半天劲,不就得到了个用户的基本信息嘛,我通过其他方式也可以得到!”。

其实不然,这还是非常有用的:

第一,这是唯一一个重不需要关注你的微信好就可获得用户信息的办法;

第二,我们来设想一下下面场景:如果我们开发一个系统想过没想过不要用户名和密码了?用户登录,并授权以后,进入我们的系统,我系统里面存放着这个微信号(OPENID)对应的权限的功能。这样我再也不用担心用户忘记密码或者密码泄露的事情了,因为这些事情微信已经帮助给做了。说到这里可能你还会问:“那岂不是每个人必须有微信号”,我先不说这里我们做的就是微信平台的应用,也不说腾讯有多大的野心,这种OAuth协议已经在微博,google,baidu,邮箱等广泛应用,我做他们响应的接口,你就说一个上用你系统的人,没有微信还不能有微博,google,baidu这些帐号,没有这些帐号你还能没有个邮箱?这些我觉得因该是以后的趋势。

何况,随着微信的完善,以后或许我们拿到的不仅是用户的基本信息,还有用户朋友圈的帖子,图片,用户的喜好等等,这些都为我们新开发的系统提供了有效的可分析的数据!


更多0

接着上次的理论,我们这次来研究用代码实现“网页授权获取用户基本信息”,首先我们需要一个链接指向微信的授权页面,在微信开发平台中已经说了,这个链接必须在微信客户端中打开,那么我们就干脆使用文本消息来完成吧,也就是说当我们发送“授权”两个字的时候,微信给我们一个链接,我们点击这个链接然后进入“授权页面”。首先改造一下我们OnLoad函数:

[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. if (wx.MsgType == "text" && wx.Content == "你好")  
  2.              {  
  3.                   
  4.                  res = sendTextMessage(wx, "你好,欢迎使用北京永杰友信科技有限公司公共微信平台!");  
  5.              }  
  6.              else if (wx.MsgType == "text" && wx.Content == "授权")  
  7.              {  
  8.                  string MyAppid = "wx043225275885dafd";  
  9.                  string RedirectUri = "http://wx.4ugood.net/OAuthRedirectUri.aspx";  
  10.                  string URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + MyAppid + "&redirect_uri=" + RedirectUri + "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect" ;     
  11.                  string Str = "<a href='" + URL + "'>授权页面</a>";  
  12.                  res = sendTextMessage(wx, Str);  
  13.              }  
  14.              else if (wx.MsgType == "voice")  
  15.              {  
  16.                  res = sendTextMessage(wx, wx.Recognition);  
  17.              }  
  18.              else if (wx.MsgType == "location")  
  19.              {  
  20.                  res = sendTextMessage(wx, "您发送的位置是:" + wx.Label + ";纬度是:" + wx.Location_X + ";经度是:" + wx.Location_Y + ";缩放比例为:" + wx.Scale);  
  21.              }  
  22.              else  
  23.              {  
  24.                  res = sendTextMessage(wx, "你好,未能识别消息!");  
  25.              }  

其中,MyAppid不用说了,RedirectUri 是我们跳转后的网页,等会儿就会看到代码,URL是微信给出的格式,我们直接使用就OK了。这样就会反馈一个链接,点击就可以进入授权的页面了。
下面我们来看看RedirectUri参数的OAuthRedirectUri.aspx页面的源码吧,因为是讲解的例子,以说明问题为主,我就简化了其中也布局,OAuthRedirectUri.aspx.cs的内容如下:
首先我们用到了两个类:OAuth_Token和OAuthUser
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class OAuth_Token  
  2. {  
  3.     public OAuth_Token()  
  4.     {  
  5.   
  6.         //  
  7.         //TODO: 在此处添加构造函数逻辑  
  8.         //  
  9.     }  
  10.     //access_token  网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同  
  11.     //expires_in    access_token接口调用凭证超时时间,单位(秒)  
  12.     //refresh_token 用户刷新access_token  
  13.     //openid    用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID  
  14.     //scope 用户授权的作用域,使用逗号(,)分隔  
  15.     public string access_token { getset; }  
  16.     public string expires_in { getset; }  
  17.     public string refresh_token { getset; }  
  18.     public string openid { getset; }  
  19.     public string scope { getset; }  
  20.   
  21. }  
  22.   
  23.   
  24. public class OAuthUser  
  25. {  
  26.     public OAuthUser()  
  27.     { }  
  28.     #region 数据库字段  
  29.     private string _openID;  
  30.     private string _searchText;  
  31.     private string _nickname;  
  32.     private string _sex;  
  33.     private string _province;  
  34.     private string _city;  
  35.     private string _country;  
  36.     private string _headimgUrl;  
  37.     private string _privilege;  
  38.     #endregion  
  39.  
  40.     #region 字段属性  
  41.     /// <summary>  
  42.     /// 用户的唯一标识  
  43.     /// </summary>  
  44.     public string openid  
  45.     {  
  46.         set { _openID = value; }  
  47.         get { return _openID; }  
  48.     }  
  49.     /// <summary>  
  50.     ///   
  51.     /// </summary>  
  52.     public string SearchText  
  53.     {  
  54.         set { _searchText = value; }  
  55.         get { return _searchText; }  
  56.     }  
  57.     /// <summary>  
  58.     /// 用户昵称   
  59.     /// </summary>  
  60.     public string nickname  
  61.     {  
  62.         set { _nickname = value; }  
  63.         get { return _nickname; }  
  64.     }  
  65.     /// <summary>  
  66.     /// 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知   
  67.     /// </summary>  
  68.     public string sex  
  69.     {  
  70.         set { _sex = value; }  
  71.         get { return _sex; }  
  72.     }  
  73.     /// <summary>  
  74.     /// 用户个人资料填写的省份  
  75.     /// </summary>  
  76.     public string province  
  77.     {  
  78.         set { _province = value; }  
  79.         get { return _province; }  
  80.     }  
  81.     /// <summary>  
  82.     /// 普通用户个人资料填写的城市   
  83.     /// </summary>  
  84.     public string city  
  85.     {  
  86.         set { _city = value; }  
  87.         get { return _city; }  
  88.     }  
  89.     /// <summary>  
  90.     /// 国家,如中国为CN   
  91.     /// </summary>  
  92.     public string country  
  93.     {  
  94.         set { _country = value; }  
  95.         get { return _country; }  
  96.     }  
  97.     /// <summary>  
  98.     /// 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空  
  99.     /// </summary>  
  100.     public string headimgurl  
  101.     {  
  102.         set { _headimgUrl = value; }  
  103.         get { return _headimgUrl; }  
  104.     }  
  105.     /// <summary>  
  106.     /// 用户特权信息,json 数组,如微信沃卡用户为(chinaunicom)其实这个格式称不上JSON,只是个单纯数组  
  107.     /// </summary>  
  108.     public string privilege  
  109.     {  
  110.         set { _privilege = value; }  
  111.         get { return _privilege; }  
  112.     }  
  113.     #endregion  
  114. }  
然后是OAuthRedirectUri.aspx.cs的全部内容:
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public partial class OAuthRedirectUri : System.Web.UI.Page  
  2. {  
  3.   
  4.     string Appid = "wx043225275885dafd";  
  5.     string appsecret = "cb4425b24ab79ef875029cf0bf326ae9";  
  6.     protected void Page_Load(object sender, EventArgs e)  
  7.     {  
  8.         if (!IsPostBack)  
  9.         {  
  10.             if (!string.IsNullOrEmpty(Request.QueryString["code"]))  
  11.             {  
  12.                 string Code = Request.QueryString["code"].ToString();  
  13.                 //获得Token  
  14.                 OAuth_Token Model = Get_token(Code);  
  15.                 //Response.Write(Model.access_token);  
  16.                 OAuthUser OAuthUser_Model = Get_UserInfo(Model.access_token, Model.openid);  
  17.                 Response.Write("用户OPENID:" + OAuthUser_Model.openid + "<br>用户昵称:" + OAuthUser_Model.nickname + "<br>性别:" + OAuthUser_Model.sex + "<br>所在省:" + OAuthUser_Model.province + "<br>所在市:" + OAuthUser_Model.city + "<br>所在国家:" + OAuthUser_Model.country + "<br>头像地址:" + OAuthUser_Model.headimgurl + "<br>用户特权信息:" + OAuthUser_Model.privilege);  
  18.                   
  19.             }  
  20.         }  
  21.     }  
  22.   
  23.     //获得Token  
  24.     protected OAuth_Token Get_token(string Code)  
  25.     {  
  26.         string Str = GetJson("https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + Appid + "&secret=" + appsecret + "&code=" + Code + "&grant_type=authorization_code");  
  27.         OAuth_Token Oauth_Token_Model = JsonHelper.ParseFromJson<OAuth_Token>(Str);  
  28.         return Oauth_Token_Model;  
  29.     }  
  30.     //刷新Token  
  31.     protected OAuth_Token refresh_token(string REFRESH_TOKEN)  
  32.     {  
  33.         string Str = GetJson("https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=" + Appid + "&grant_type=refresh_token&refresh_token=" + REFRESH_TOKEN);  
  34.         OAuth_Token Oauth_Token_Model = JsonHelper.ParseFromJson<OAuth_Token>(Str);  
  35.         return Oauth_Token_Model;  
  36.     }  
  37.     //获得用户信息  
  38.     protected OAuthUser Get_UserInfo(string REFRESH_TOKEN, string OPENID)  
  39.     {  
  40.        // Response.Write("获得用户信息REFRESH_TOKEN:" + REFRESH_TOKEN + "||OPENID:" + OPENID);  
  41.         string Str = GetJson("https://api.weixin.qq.com/sns/userinfo?access_token=" + REFRESH_TOKEN + "&openid=" + OPENID);  
  42.         OAuthUser OAuthUser_Model = JsonHelper.ParseFromJson<OAuthUser>(Str);  
  43.         return OAuthUser_Model;  
  44.     }  
  45.     protected string GetJson(string url)  
  46.     {  
  47.         WebClient wc = new WebClient();  
  48.         wc.Credentials = CredentialCache.DefaultCredentials;  
  49.         wc.Encoding = Encoding.UTF8;  
  50.         string returnText = wc.DownloadString(url);  
  51.   
  52.         if (returnText.Contains("errcode"))  
  53.         {  
  54.             //可能发生错误  
  55.         }  
  56.         //Response.Write(returnText);  
  57.         return returnText;  
  58.     }  
  59. }  

其中用到的JsonHelper类在 《微信公共服务平台开发(.Net 的实现)5-------解决access_token过期的问题》  也提到过,不再粘贴了。这样我们就实现了授权到拉取用户信息的功能了。

2 0