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分享
C#微信公众号开发的更多相关文章
- 微信公众号开发(一)--验证服务器地址的Java实现
现在主流上都用php写微信公众号后台,其实作为后端语言之一的java也可以实现. 这篇文章将对验证服务器地址这一步做出实现. 参考资料:1.慕课网-<初识java微信公众号开发>,2.微信 ...
- C#微信公众号开发系列教程三(消息体签名及加解密)
http://www.cnblogs.com/zskbll/p/4139039.html C#微信公众号开发系列教程一(调试环境部署) C#微信公众号开发系列教程一(调试环境部署续:vs远程调试) C ...
- C#微信公众号开发系列教程二(新手接入指南)
http://www.cnblogs.com/zskbll/p/4093954.html 此系列前面已经更新了两篇博文了,都是微信开发的前期准备工作,现在切入正题,本篇讲解新手接入的步骤与方法,大神可 ...
- 微信公众号开发系列教程一(调试环境部署续:vs远程调试)
http://www.cnblogs.com/zskbll/p/4080328.html 目录 C#微信公众号开发系列教程一(调试环境部署) C#微信公众号开发系列教程一(调试环境部署续:vs远程调试 ...
- NET微信公众号开发-5.0微信支付(待测试)
开发前准备. 1.0微信支付官方开发者文档 2.0官方demo下载 我们用c#所以选择.net版本 不过这个官方的demo根本跑步起来 3.0官方demo运行起来解决方案 4.0微信支付官方.net版 ...
- .NET开发者如何愉快的进行微信公众号开发
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:这篇文章只是一个如何提高开发效率的简单指导和记录,不会涉及具体的微信公众号开发内容. ...
- 微信公众号开发之被逼学web服务端1-----使用SecureCRT连接Linux服务器
做Android的进新公司后安排做微信公众号开发,这基本是后台和前端的活都要由小白的我来做,这两天基本成鸭子了,被填的满满的,却还是不够,博文仅作记录,希望能给后来的小白一点参考吧 今天做的是如何配置 ...
- 利用OpenShift托管Node.js Web服务进行微信公众号开发
最近写了一个微信的翻译机器人.用户只要关注该公众号,发送英文的消息,就能收到中文翻译的回复.有兴趣的读者可以扫描下面的二维码关注该公众号,尝试发送英文单词试试看.(有时候第一次发送单词会收到“该公众号 ...
- .net微信公众号开发——消息与事件
作者:王先荣 本文介绍如何处理微信公众号开发中的消息与事件,包括:(1)消息(事件)概况:(2)验证消息的真实性:(3)解析消息:(4)被动回复消息:(5)发送其他消息. 开源项目地址:h ...
- C#微信公众号开发系列教程六(被动回复与上传下载多媒体文件)
微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C ...
随机推荐
- CSS – Logical Properties
前言 续上一篇介绍了各种语言的阅读方向. 这一篇来讲一下 Logical Properties. 它与 left to right, right to left, horizontal, vertic ...
- [rCore学习笔记 027]地址空间
写在前面 本随笔是非常菜的菜鸡写的.如有问题请及时提出. 可以联系:1160712160@qq.com GitHhub:https://github.com/WindDevil (目前啥也没有 引言 ...
- 开发板、windows、虚拟机互相ping通/ VMNET0、VMNET1、VMNET8释义
当前环境:板子通过网线连接windows 问题: 我当前的板子可以ping通windows,windows也能ping通ubuntu.但是板子却ping不通ubuntu. 原因: ubuntu通过NA ...
- Vue Cli 创建项目在 GitHub 部署 history 路由模式
1.修改打包路径 在 vue.config.js 中添加 publicPath 配置,其中 teambition-vue 是你项目的 github 名字.否则会找不到资源. module.expo ...
- C# 中的四种整形数据
// C# 中有四种整数类型 byte short int long byte bMax = byte.MaxValue; /// 255 最大值 byte bMin = byte.MinValue; ...
- 谈谈 keep-alive 组件,以及它们的实现原理
keep-alive 组件的使用场景: 我们切换 2 个组件的时候,2个组件会轮流被销毁创建,但是现在需求,切换到一个组件,另一个组件不会别销毁,会保留原来的状态 :就要使用 vue 内置的组件 ke ...
- .NET使用Graphql的演示
Graphql是什么?先来一段AI给的回答: GraphQL是一种为API设计的查询语言,与REST相比,它提供了更高效.强大和灵活的方法来与数据交互.GraphQL由Facebook于2012年开发 ...
- KubeKey 部署 K8s v1.28.8 实战
在某些生产环境下,我们仅需要一个原生的 K8s 集群,无需部署 KubeSphere 这样的图形化管理控制台.在我们已有的技术栈里,已经习惯了利用 KubeKey 部署 KubeSphere 和 K8 ...
- 快速部署单服务器oracle12c
docker pull docker.io/truevoly/oracle-12c mkdir -p /usr/local/oracle/data_temp chmod 777 /usr/local/ ...
- 一文彻底弄清Redis的布隆过滤器
布隆过滤器(Bloom Filter)是一种空间效率极高的数据结构,用于快速判断一个元素是否在集合中.它能够节省大量内存,但它有一个特点:可能存在误判,即可能会认为某个元素存在于集合中,但实际上不存在 ...