当前位置: 代码迷 >> C# >> C#微信大众号开发入门教程
  详细解决方案

C#微信大众号开发入门教程

热度:493   发布时间:2016-04-28 08:28:58.0
C#微信公众号开发入门教程

首先打开开发文档:

微信公众号开发者文档:http://mp.weixin.qq.com/wiki/home/index.html

 

一、创建测试账号

可以先申请一个开发者测试账号

用自己微信扫描后即可获得测试账号:

就有了appId 和 appsecret了,微信号在右上角。

 

二、获取access_token (这个access_token是通过appID 和 appsecret来生成的,只要是向微信服务器发送请求都需要带上这个access_token。)

打开 微信公众平台接口调试工具

 

程序生成access_token,解决2小时失效的问题,2小时候会重新生成一个。

access_token帮助类:

using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Xml.Linq;namespace YangYiEcormerce.WeChat.Web.Common{    /// <summary>    /// AccessToken帮助类    /// </summary>    public class AccessTokenHelp    {        //填写自己微信的秘钥        private static string appId = System.Configuration.ConfigurationManager.AppSettings["WeChatAppId"];        private static string appSecret = System.Configuration.ConfigurationManager.AppSettings["WeChatAppSecret"];        private static DateTime GetAccessToken_Time;        /// <summary>        /// 过期时间为7200秒        /// </summary>        private static int Expires_Period = 7200;        /// <summary>        ///         /// </summary>        private static string mAccessToken;        /// <summary>        ///         /// </summary>        public static string AccessToken        {            get            {                //如果为空,或者过期,需要重新获取                if (string.IsNullOrEmpty(mAccessToken) || HasExpired())                {                    //获取                    mAccessToken = GetAccessToken(appId, appSecret);                }                return mAccessToken;            }        }        /// <summary>        ///         /// </summary>        /// <param name="appId"></param>        /// <param name="appSecret"></param>        /// <returns></returns>        private static string GetAccessToken(string appId, string appSecret)        {            string url = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}", appId, appSecret);            string result = HttpUtility.GetData(url);            XDocument doc = CommonHelp.ParseJsonToXML(result, "root");            XElement root = doc.Root;            if (root != null)            {                XElement access_token = root.Element("access_token");                if (access_token != null)                {                    GetAccessToken_Time = DateTime.Now;                    if (root.Element("expires_in") != null)                    {                        Expires_Period = int.Parse(root.Element("expires_in").Value);                    }                    return access_token.Value;                }                else                {                    GetAccessToken_Time = DateTime.MinValue;                }            }            return null;        }        /// <summary>        /// 判断Access_token是否过期        /// </summary>        /// <returns>bool</returns>        private static bool HasExpired()        {            if (GetAccessToken_Time != null)            {                //过期时间,允许有一定的误差,一分钟。获取时间消耗                if (DateTime.Now > GetAccessToken_Time.AddSeconds(Expires_Period).AddSeconds(-60))                {                    return true;                }            }            return false;        }    }}
View Code

HttpUtility类:

 /// <summary>    ///Http帮助类    /// </summary>    public class HttpUtility    {        /// <summary>        /// 发送请求        /// </summary>        /// <param name="url">Url地址</param>        /// <param name="data">数据</param>        public static string SendHttpRequest(string url, string data)        {            return SendPostHttpRequest(url, "application/x-www-form-urlencoded", data);        }        /// <summary>        ///         /// </summary>        /// <param name="url"></param>        /// <returns></returns>        public static string GetData(string url)        {            return SendGetHttpRequest(url, "application/x-www-form-urlencoded");        }        /// <summary>        /// 发送请求        /// </summary>        /// <param name="url">Url地址</param>        /// <param name="method">方法(post或get)</param>        /// <param name="method">数据类型</param>        /// <param name="requestData">数据</param>        public static string SendPostHttpRequest(string url, string contentType, string requestData)        {            WebRequest request = (WebRequest)HttpWebRequest.Create(url);            request.Method = "POST";            byte[] postBytes = null;            request.ContentType = contentType;            postBytes = Encoding.UTF8.GetBytes(requestData);            request.ContentLength = postBytes.Length;            using (Stream outstream = request.GetRequestStream())            {                outstream.Write(postBytes, 0, postBytes.Length);            }            string result = string.Empty;            using (WebResponse response = request.GetResponse())            {                if (response != null)                {                    using (Stream stream = response.GetResponseStream())                    {                        using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))                        {                            result = reader.ReadToEnd();                        }                    }                }            }            return result;        }        /// <summary>        /// 发送请求        /// </summary>        /// <param name="url">Url地址</param>        /// <param name="method">方法(post或get)</param>        /// <param name="method">数据类型</param>        /// <param name="requestData">数据</param>        public static string SendGetHttpRequest(string url, string contentType)        {            WebRequest request = (WebRequest)HttpWebRequest.Create(url);            request.Method = "GET";            request.ContentType = contentType;            string result = string.Empty;            using (WebResponse response = request.GetResponse())            {                if (response != null)                {                    using (Stream stream = response.GetResponseStream())                    {                        using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))                        {                            result = reader.ReadToEnd();                        }                    }                }            }            return result;        }    }
View Code

ParseJsonToXML方法: (需要引入Newtonsoft.Json.dll)

        /// <summary>        /// 将Json转化为XML        /// </summary>        /// <param name="json"></param>        /// <param name="rootName"></param>        /// <returns></returns>        public static XDocument ParseJsonToXML(string json, string rootName)        {            return JsonConvert.DeserializeXNode(json, rootName);        }
View Code

程序调用获取access_token:

string access_token = Common.AccessTokenHelp.AccessToken;

 

三、创建菜单:

还是使用调试工具来创建:

JSON格式菜单内容:下面创建的都是一级菜单,更多详细的菜单创建,参考说明文档>>

{    "button": [        {            "name": "商城",             "type": "view",             "url": "http://shop.com"  //点击菜单访问网址        },        {            "name": "防伪扫描",             "type": "scancode_push",             "key": "FangweiScan"      //点击调用微信二维码扫描,是网址直接访问,是文本则显示文本内容        },        {            "name": "订单查询",             "type": "click",             "key": "OrderQuery"       //点击出发click事件,向我们配置的API地址进行请求        }    ]}

请求成功后,取消微信号关注并退出微信,重新进入关注,应该就可以看到添加好的文档了。

想删除重新创建菜单,调用菜单删除就可以了。

 

效果:

 

四、开发接口、处理文本和事件 (当用户使用微信发送消息或者单击菜单出发事件,就会想配置的API发送请求,API进行处理响应)    消息回复参考文档>>

接口是一个一般处理程序: 

using System;using System.Collections.Generic;using System.Web;using System.IO;using System.Text;using System.Web.Security;using System.Xml;namespace weixin_api{    /// <summary>    /// interfaceTest 的摘要说明    /// </summary>    public class interfaceTest : IHttpHandler    {        public void ProcessRequest(HttpContext param_context)        {            string postString = string.Empty;            //用户发送消息或点击等事件一般都是POST过来,微信服务器向接口发送POST请求,根据请求我们进行处理反馈            if (HttpContext.Current.Request.HttpMethod.ToUpper() == "POST")            {                using (Stream stream = HttpContext.Current.Request.InputStream)                {                    Byte[] postBytes = new Byte[stream.Length];                    stream.Read(postBytes, 0, (Int32)stream.Length);                    postString = Encoding.UTF8.GetString(postBytes);                    Handle(postString);                }            }            else            {                //第一次配置接口地址的时候,微信服务器会向接口发送一个GET请求来验证你的接口地址                InterfaceTest();            }        }        /// <summary>        /// 处理信息并应答        /// </summary>        private void Handle(string postStr)        {            messageHelp help = new messageHelp();            string responseContent = help.ReturnMessage(postStr);            HttpContext.Current.Response.ContentEncoding = Encoding.UTF8;            HttpContext.Current.Response.Write(responseContent);        }        //成为开发者url测试,返回echoStr        public void InterfaceTest()        {            string token = "token";            if (string.IsNullOrEmpty(token))            {                return;            }            //微信服务器会将下面几个参数发送到接口,接口这边返回接收到的echoStr就说明验证通过,            //主要为了防止别人盗用你的接口,我这边没做逻辑判断直接返回接收到的echoStr来通过验证            string echoString = HttpContext.Current.Request.QueryString["echoStr"];            string signature = HttpContext.Current.Request.QueryString["signature"];            string timestamp = HttpContext.Current.Request.QueryString["timestamp"];            string nonce = HttpContext.Current.Request.QueryString["nonce"];            if (!string.IsNullOrEmpty(echoString))            {                HttpContext.Current.Response.Write(echoString);                HttpContext.Current.Response.End();            }        }        public bool IsReusable        {            get            {                return false;            }        }    }}

 

接受/发送消息帮助类

using System;using System.Collections.Generic;using System.Web;using System.IO;using System.Text;using System.Web.Security;using System.Xml;namespace weixin_api{    /// <summary>    /// 接受/发送消息帮助类    /// </summary>    public class messageHelp    {        //返回消息        public string ReturnMessage(string postStr)        {            string responseContent = "";            XmlDocument xmldoc = new XmlDocument();            xmldoc.Load(new System.IO.MemoryStream(System.Text.Encoding.GetEncoding("GB2312").GetBytes(postStr)));            XmlNode MsgType = xmldoc.SelectSingleNode("/xml/MsgType");            if (MsgType != null)            {                switch (MsgType.InnerText)                {                    case "event":                        responseContent = EventHandle(xmldoc);//事件处理                        break;                    case "text":                        responseContent = TextHandle(xmldoc);//接受文本消息处理                        break;                    default:                        break;                }            }            return responseContent;        }        //事件        public string EventHandle(XmlDocument xmldoc)        {            string responseContent = "";            XmlNode Event = xmldoc.SelectSingleNode("/xml/Event");            XmlNode EventKey = xmldoc.SelectSingleNode("/xml/EventKey");            XmlNode ToUserName = xmldoc.SelectSingleNode("/xml/ToUserName");            XmlNode FromUserName = xmldoc.SelectSingleNode("/xml/FromUserName");            XmlNode ScanResult = xmldoc.SelectSingleNode("/xml/ScanCodeInfo/ScanResult");            if (Event != null)            {                //菜单单击事件                if (Event.InnerText.Equals("CLICK"))                {                    if (EventKey.InnerText.Equals("OrderQuery"))//点击订单查询  这个OrderQuery就是菜单里面的key                    {                        responseContent = string.Format(ReplyType.Message_Text,                            FromUserName.InnerText,                            ToUserName.InnerText,                            DateTime.Now.Ticks,                            "正在开发中,敬请期待!");                    }                }                else if (Event.InnerText.Equals("scancode_waitmsg")) //扫码推事件且弹出“消息接收中”提示框的事件推送                 {                    if (EventKey.InnerText.Equals("FangweiScan")) //点击防伪扫描                    {                        //....处理返回逻辑                    }                }            }            return responseContent;        }        //接受文本消息        public string TextHandle(XmlDocument xmldoc)        {            string responseContent = "";            XmlNode ToUserName = xmldoc.SelectSingleNode("/xml/ToUserName");            XmlNode FromUserName = xmldoc.SelectSingleNode("/xml/FromUserName");            XmlNode Content = xmldoc.SelectSingleNode("/xml/Content");            if (Content != null)            {                //回复文本信息                responseContent = string.Format(ReplyType.Message_Text,                    FromUserName.InnerText,                    ToUserName.InnerText,                    DateTime.Now.Ticks,                    "欢迎使用微信公共账号,您输入的内容为:" + Content.InnerText);            }            return responseContent;        }        //写入日志        public void WriteLog(string text)        {            StreamWriter sw = new StreamWriter(HttpContext.Current.Server.MapPath(".") + "\\log.txt", true);            sw.WriteLine(text);            sw.Close();        }    }    //回复类型    public class ReplyType    {        /// <summary>        /// 普通文本消息        /// </summary>        public static string Message_Text        {            get            {                return @"<xml>                            <ToUserName><![CDATA[{0}]]></ToUserName>                            <FromUserName><![CDATA[{1}]]></FromUserName>                            <CreateTime>{2}</CreateTime>                            <MsgType><![CDATA[text]]></MsgType>                            <Content><![CDATA[{3}]]></Content>                            </xml>";            }        }        /// <summary>        /// 图文消息主体        /// </summary>        public static string Message_News_Main        {            get            {                return @"<xml>                            <ToUserName><![CDATA[{0}]]></ToUserName>                            <FromUserName><![CDATA[{1}]]></FromUserName>                            <CreateTime>{2}</CreateTime>                            <MsgType><![CDATA[news]]></MsgType>                            <ArticleCount>{3}</ArticleCount>                            <Articles>                            {4}                            </Articles>                            </xml> ";            }        }        /// <summary>        /// 图文消息项        /// </summary>        public static string Message_News_Item        {            get            {                return @"<item>                            <Title><![CDATA[{0}]]></Title>                             <Description><![CDATA[{1}]]></Description>                            <PicUrl><![CDATA[{2}]]></PicUrl>                            <Url><![CDATA[{3}]]></Url>                            </item>";            }        }    }}
View Code

 

五、发送模板消息  (官方说明文档>>)

在公众平台创建模板:

发送模板消息帮助类:

 public class TemplateMessage    {        static JavaScriptSerializer Jss = new JavaScriptSerializer();        /// <summary>        /// 给指定的用户发送模板消息        /// </summary>        /// <param name="openId">用户标识openid</param>        /// <param name="templateId">对应的模板id</param>        /// <param name="data">对应模板的参数</param>        /// <param name="url">点击对应消息弹出的地址</param>        /// <param name="topcolor">颜色</param>        /// <returns>返回json数据包</returns>        public static string SendTemplate(string openId, string templateId, object data, string url, string topcolor = "#173177")        {            string access_token = AccessTokenHelp.AccessToken;            var msgData = new            {                touser = openId,                template_id = templateId,                topcolor = topcolor,                url = url,                data = data            };            string postData = Jss.Serialize(msgData);            return HttpUtility.SendHttpRequest("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + access_token, postData);        }        /// <summary>        /// 给指定的用户发送模板消息        /// </summary>        /// <param name="openId">用户标识openid</param>        /// <param name="templateId">对应的模板id</param>        /// <param name="data">对应模板的参数</param>        /// <param name="topcolor">颜色</param>        /// <returns>返回json数据包</returns>        public static string SendTemplate(string openId, string templateId, object data, string topcolor = "#173177")        {            string access_token = AccessTokenHelp.AccessToken;            var msgData = new            {                touser = openId,                template_id = templateId,                topcolor = topcolor,                data = data            };            string postData = Jss.Serialize(msgData);            return HttpUtility.SendHttpRequest("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + access_token, postData);        }    }
View Code

发送模板消息调用:

var data = new                        {                            first = new                            {                                value = "恭喜你购买成功",                                color = "#173177"                            }                        };                        string templateId = "ibrQIRAaFkbeRNKpj9SbuJ0Rgs6q1ZTpsNkdf31lZwM";                        TemplateMessage.SendTemplate(FromUserName.InnerText, templateId, data);
View Code

效果:

 

六、接口开发完成,配置接口信息

配置验证通过后,用户发消息或事件,接口拿到信息就可以做出处理反馈了。

接口URL验证:

  public void ProcessRequest(HttpContext context)        {            string postString = string.Empty;            if (HttpContext.Current.Request.HttpMethod.ToUpper() == "POST")            {                using (Stream stream = HttpContext.Current.Request.InputStream)                {                    Byte[] postBytes = new Byte[stream.Length];                    stream.Read(postBytes, 0, (Int32)stream.Length);                    postString = Encoding.UTF8.GetString(postBytes);                    Handle(postString);                }            }            else            {                //验证签名                if (CheckSignature())                {                    HttpContext.Current.Response.Write(HttpContext.Current.Request.QueryString["echoStr"]);                }                else                {                    HttpContext.Current.Response.Write("error");                }            }        }
View Code

验证签名方法:

 /// <summary>        /// 检查签名        /// </summary>        /// <param name="request"></param>        /// <returns></returns>        private bool CheckSignature()        {            string token = System.Configuration.ConfigurationManager.AppSettings["WeChatToken"];            string signature = HttpContext.Current.Request.QueryString["signature"];            string timestamp = HttpContext.Current.Request.QueryString["timestamp"];            string nonce = HttpContext.Current.Request.QueryString["nonce"];            List<string> list = new List<string>();            list.Add(token);            list.Add(timestamp);            list.Add(nonce);            //排序            list.Sort();            //拼串            string input = string.Empty;            foreach (var item in list)            {                input += item;            }            //加密            string new_signature = CommonHelp.SHA1Encrypt(input);            //验证            if (new_signature == signature)            {                return true;            }            else            {                return false;            }        }
View Code

签名中的SHA1Encrypt加密算法:

 /// <summary>        /// SHA1加密        /// </summary>        /// <param name="intput">输入字符串</param>        /// <returns>加密后的字符串</returns>        public static string SHA1Encrypt(string intput)        {            byte[] StrRes = Encoding.Default.GetBytes(intput);            HashAlgorithm mySHA = new SHA1CryptoServiceProvider();            StrRes = mySHA.ComputeHash(StrRes);            StringBuilder EnText = new StringBuilder();            foreach (byte Byte in StrRes)            {                EnText.AppendFormat("{0:x2}", Byte);            }            return EnText.ToString();        }
View Code

此时,如果填写的Token和接口中的Token不一致就会验证失败,就可以防止其他人盗用你的接口了。

 

七、源码下载

C#微信公众号开发简易Demo源码

 

八、相关学习资源推荐:

1.net微信开发

2.C#开发微信门户及应用 (比较全,winform实现,但没完整源码)

3.用c#开发微信 系列汇总

4.微信公众平台开发(php语言开发)

 

时间匆忙,写的不是很详细,有时间再慢慢完善。

 

3楼teak.Zou
帮大忙了,楼主辛苦。
2楼bruce.cui
学习学习!!!!!
1楼freewzx2005
学习学习