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分享