C#微信公眾號開發


C#微信公眾號開發

一》 准備

用自己的微信掃碼登陸,然后就可以獲取就有了appId 和 appsecret。

二》獲取access_token

打開 微信公眾平台接口調試工具


這個access_token是通過appID 和 appsecret來生成的,access_token 有效期為 兩個小時(7200秒),一天可以獲取2000次,只要是向微信服務器發送請求都需要帶上這個access_token

  /// <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;
        }

通過 string access_token = Common.AccessTokenHelp.AccessToken; 就可以獲取accesstoken

三》創建菜單

通過測試接口來處理

{
    "button": [
        {
            "name": "迷戀自留地", 
            "type": "view", 
            "url": "https://hunji.xyz"  //點擊菜單訪問網址
        },
        {
            "name": "防偽掃描", 
            "type": "scancode_push", 
            "key": "FangweiScan"      //點擊調用微信二維碼掃描,是網址直接訪問,是文本則顯示文本內容
        },
        {
            "name": "訂單查詢", 
            "type": "click", 
            "key": "OrderQuery"       //點擊出發click事件,向我們配置的API地址進行請求
        }
    ]
}

掃碼關注公眾號就ok,更多的按鈕參考:微信開發文檔

請求成功后,取消微信號關注並退出微信,重新進入關注,應該就可以看到添加好的文檔了。

想刪除重新創建菜單,調用菜單刪除就可以了。

四》開發接口、處理文本和事件

當用戶使用微信發送消息或者單擊菜單出發事件,就會向配置的API發送請求,API進行處理響應 : 消息回復參考文檔

c#一般多半是一般處理程序,目前是net6都已經出來了,處理方式大差不差,但還是有些不一樣的地方。net5 具體的代碼實現請查閱下篇文章,在這里先埋個坑

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>";
            }
        }


    }
}

五》發送模板消息

首先在后台添加測試的模板,獲取到消息模板的id

在這里插入圖片描述

發送模板消息幫助類:

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);
        }

    }

發送模板消息調用:

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


參考鏈接

六》接口驗證

配置驗證通過后,用戶發消息或事件,接口拿到信息就可以做出處理反饋了

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");
                }
            }
        }

簽名方法

/// <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;
            }
        }

簽名中的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();
        }

推薦公眾號:net分享
我的公眾號


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM