C#微信公众号开发-MVC模式公共类封装
第一部分:基础配置
第一步:注册微信公众账号
如果开发测试阶段可以打开测试链接地址,注册测试公众号。测试账号除了不能与正式账号通信外其他什么高级接口的都可以实现。
测试号管理地址:http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
账号开通成功后系统会分配两个账号信息:appID、appsecret作为此账号的标识。
第二步:接口配置信息
这里的接口配置主要为保证微信能与你所建的站点进行数据交互,并且数据的传递要符合规则。
这里需要完成两个参数配置:
URL:你可以在自己的项目中新建一个action或者其他在微信访问此地址时能返回数据就行。
Token:一个建立两者对话的口令,设置完成后项目中也需要配置同样的Token方可正常通信。
这里你可以在定义的URL中直接返回微信的请求“echostr”参数值,当然正常情况下是需要按照规则验证数据的请求安全后返回。
可以在请求的URL指定的Action中按照微信官方提示,做如下签名验证(这样做属于安全的):
public ActionResult Webcatch()
{
string token = "loyung";
if (string.IsNullOrWhiteSpace(token))
{
return null;
} string echoStr = Request.QueryString["echoStr"];//随机字符串
string signature = Request.QueryString["signature"];//微信加密签名
string timestamp = Request.QueryString["timestamp"];//时间戳
string nonce = Request.QueryString["nonce"];//随机数
string[] ArrTmp = { token, timestamp, nonce };
Array.Sort(ArrTmp); //字典排序
string tmpStr = string.Join("", ArrTmp);
tmpStr = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1");
tmpStr = tmpStr.ToLower();
if (tmpStr == signature)
{
return Content(echoStr);
}
else
{
return Content("false");
}
}
第三步:JS接口安全域名配置
按照页面的提示,配置上需要做微信接口的域名配置。
第二部分:关于微信操作类的封装
以上第一部分为入门级的简单操作,如果要把微信的整个接口开发完,当然要思考怎样把微信的每个接口无缝对接到现有系统。
思路:1.将接口的常用返回值作为一种类型去接收。
2.微信接口都可以使用GET请求,可以封装Get数据请求处理工厂。
3.最重要的莫过于每次请求都需要有效的access_token,由于access_token的有效期只有两个小时,这里我们采用文件的形式记录access_token,并在每次使用前检查access_token是否可用。
4.代码文件:Model WeiXinModel.cs存放数据要被序列化的实体类结构,Control WeChat.cs用来封装所有接口的调用以及对access_token的处理。View 直接调用WeChat封装接口。
由于所有接口实在太多,这里做一个获取所有关注粉丝信息的Demo。
Model WeiXinModel.cs
/*
* 创建时间:2016-07-19
* 创建人:刘自洋
* 说明:此文件下包含所有微信实体类
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; namespace Ecio_Admin.Models
{
#region 系统返回信息
/// <summary>
/// 系统返回信息
/// </summary>
/// <typeparam name="T">指定返回类型</typeparam>
public class wx_backdata<T>
{
/// <summary>
/// 接口返回数据状态true成功|false失败
/// </summary>
public bool ResponseState;
/// <summary>
/// 接口返回正确数据
/// </summary>
public T ResponseData;
/// <summary>
/// 接口返回错误时间
/// </summary>
public wx_apperror ErrorData;
}
#endregion #region 微信接口返回错误类
/// <summary>
/// 微信接口返回错误类
/// </summary>
public class wx_apperror
{
/// <summary>
/// 接口错误代码
/// </summary>
public string errcode;
/// <summary>
/// 接口错误消息
/// </summary>
public string errmsg;
}
#endregion #region 获取接口返回Token
/// <summary>
/// 获取接口返回凭证Token
/// </summary>
public class wx_access_token
{
/// <summary>
/// 获取到的凭证
/// </summary>
public string access_token;
/// <summary>
/// 凭证有效时间,单位:秒
/// </summary>
public string expires_in;
} #endregion #region 获取此用户OpenID
/// <summary>
/// 获取用户OpenID列表
/// </summary>
public class wx_openidlist
{
/// <summary>
/// 关注该公众账号的总用户数
/// </summary>
public string total;
/// <summary>
/// 拉取的OPENID个数,最大值为10000
/// </summary>
public string count;
/// <summary>
/// 列表数据,OPENID的列表
/// </summary>
public data data;
/// <summary>
/// 拉取列表的最后一个用户的OPENID
/// </summary>
public string next_openid;
}
/// <summary>
/// openid对象
/// </summary>
public class data
{
/// <summary>
/// 用户标识
/// </summary>
public List<string> openid;
}
#endregion #region 获取用户个人信息
public class wx_user_info
{
/// <summary>
/// 是否订阅该公众号0没有关注|1已关注
/// </summary>
public string subscribe;
/// <summary>
/// 用户的标识,对当前公众号唯一
/// </summary>
public string openid;
/// <summary>
/// 用户的昵称
/// </summary>
public string nickname;
/// <summary>
/// 用户的性别0未知|1男性|2女性
/// </summary>
public string sex;
/// <summary>
/// 用户所在城市
/// </summary>
public string city;
/// <summary>
/// 用户所在国家
/// </summary>
public string country;
/// <summary>
/// 用户所在省份
/// </summary>
public string province;
/// <summary>
/// 用户的语言
/// </summary>
public string language;
/// <summary>
/// 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像)
/// </summary>
public string headimgurl;
/// <summary>
/// 用户关注时间
/// </summary>
public string subscribe_time;
/// <summary>
/// 绑定到微信开放平台唯一标识
/// </summary>
public string unionid;
/// <summary>
/// 粉丝备注
/// </summary>
public string remark;
/// <summary>
/// 用户所在的分组ID(兼容旧的用户分组接口)
/// </summary>
public string groupid;
/// <summary>
/// 用户被打上的标签ID列表
/// </summary>
public List<string> tagid_list;
}
#endregion
}
Control WeChat.cs
/*
* 创建时间:2016-07-18
* 创建人:刘自洋
* 说明:此类包含微信相关配置,接口凭据获取、更新,以及常用接口调用。
*/
using Ecio_Admin.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml; namespace Ecio_Admin.Common
{
/// <summary>
/// 微信配置、操作类
/// </summary>
public class WeChat
{ #region 【构造】微信配置
/// <summary>
/// 初始化微信参数配置
/// </summary>
public WeChat()
{
XmlDocument Xml = new XmlDocument();
Xml.Load(HttpContext.Current.Server.MapPath("~/App_Data/Config/WeiXin.config"));
XmlNode appid = Xml.SelectSingleNode("weixin/appid");
XmlNode appsecret = Xml.SelectSingleNode("weixin/appsecret");
XmlNode accesstoken = Xml.SelectSingleNode("weixin/accesstoken");
XmlNode token = Xml.SelectSingleNode("weixin/token");
if (appid != null)
{
this.appid = appid.InnerText;
}
if (appsecret != null)
{
this.secret = appsecret.InnerText;
}
if (accesstoken != null)
{
if (check_access_token())
{
this.accesstoken = accesstoken.InnerText;
}
else
{
var backdate = get_access_token();
//更新当前access_token
if (backdate.ResponseState)
{
this.accesstoken = backdate.ResponseData.access_token;
accesstoken.InnerText = backdate.ResponseData.access_token;
Xml.Save(HttpContext.Current.Server.MapPath("~/App_Data/Config/WeiXin.config"));
}
}
}
if (token != null)
{
this.token = token.InnerText;
} }
#endregion #region 【配置】微信基础参数
/// <summary>
/// 服务器标识
/// </summary>
private string token = "loyung";
/// <summary>
/// 开发者ID(AppID(应用ID))
/// </summary>
private string appid = "wx**********";
/// <summary>
/// (AppSecret(应用密钥))
/// </summary>
private string secret = "************ ";
/// <summary>
///接口连接凭据
/// </summary>
private string accesstoken = ""; #endregion #region 【验证】微信签名
/// <summary>
/// 微信签名验证
/// </summary>
/// <param name="nonce">随机字符串 </param>
/// <param name="timestamp">时间戳 </param>
/// <param name="signature">微信加密签名</param>
/// <returns>验签是否成功true成功|false失败</returns>
public bool CheckSign(string nonce, string timestamp, string signature)
{
string[] ArrTmp = { token, timestamp, nonce };
Array.Sort(ArrTmp); //字典排序
string tmpStr = string.Join("", ArrTmp);
tmpStr = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1");
tmpStr = tmpStr.ToLower();
if (tmpStr == signature)
{
return true;
}
else
{
return false;
}
}
#endregion #region 【验证】access_token是否失效
/// <summary>
/// 根据接口返回代码42001验证是否可用
/// </summary>
/// <returns>true可用|false失效</returns>
public bool check_access_token()
{
XmlDocument Xml = new XmlDocument();
Xml.Load(HttpContext.Current.Server.MapPath("~/App_Data/Config/WeiXin.config"));
XmlNode access_token = Xml.SelectSingleNode("weixin/accesstoken");
if (access_token != null)
{
this.accesstoken = access_token.InnerText;
}
string Url = "https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=" + this.accesstoken;
string GetResult = ToolKit.GetData(Url);
if (GetResult.IndexOf("errcode") != -)
{
var ErrorMessage = JsonConvert.DeserializeObject<wx_apperror>(GetResult);
if (ErrorMessage.errcode == "")
{
return false;
}
return false;
}
else
{
return true;
}
}
#endregion #region 【通用】获取可用接口凭据
/// <summary>
/// 获取可用的接口凭据
/// </summary>
public string Accesstoken()
{
if (!check_access_token())
{
XmlDocument Xml = new XmlDocument();
Xml.Load(HttpContext.Current.Server.MapPath("~/App_Data/Config/WeiXin.config"));
XmlNode access_token = Xml.SelectSingleNode("weixin/accesstoken");
if (access_token != null)
{
var backdate = get_access_token();
//更新当前access_token
if (backdate.ResponseState)
{
this.accesstoken = backdate.ResponseData.access_token;
access_token.InnerText = backdate.ResponseData.access_token;
Xml.Save(HttpContext.Current.Server.MapPath("~/App_Data/Config/WeiXin.config"));
}
}
}
return this.accesstoken;
}
#endregion #region【通用】获取JSON指定类型返回值
/// <summary>
/// 【通用】获取JSON指定类型返回值
/// </summary>
/// <typeparam name="T">指定非错误的返回类型</typeparam>
/// <param name="JsonData">序列化前JSON字符</param>
/// <returns>JSON序列化后数据</returns>
public wx_backdata<T> GetJson<T>(string JsonData)
{
var result = new wx_backdata<T>();
if (JsonData.IndexOf("errcode") != -)
{
result.ResponseState = false;
result.ErrorData = JsonConvert.DeserializeObject<wx_apperror>(JsonData);
}
else
{
result.ResponseState = true;
result.ResponseData = JsonConvert.DeserializeObject<T>(JsonData);
}
return result;
}
#endregion #region 【access_token】获取唯一接口调用凭据
/// <summary>
/// 获取唯一接口调用凭据access_token
/// </summary>
/// <returns>access_token获取结果对象</returns>
public wx_backdata<wx_access_token> get_access_token()
{
string Url = "https://api.weixin.qq.com/cgi-bin/token?";
string grant_type = "client_credential";
string GetResult = ToolKit.GetData(Url + "grant_type=" + grant_type + "&appid=" + appid + "&secret=" + secret);
return GetJson<wx_access_token>(GetResult);
}
#endregion #region【OpenId】 获取用户列表
/// <summary>
/// 获取粉丝微信OpenId
/// </summary>
/// <returns>接口返回值</returns>
public wx_backdata<wx_openidlist> GetOpenIdList()
{
string Url = "https://api.weixin.qq.com/cgi-bin/user/get?";
string GetResult = ToolKit.GetData(Url + "access_token=" + this.Accesstoken() + "&next_openid=");
return GetJson<wx_openidlist>(GetResult);
}
#endregion #region 【用户信息】获取指定用户信息
/// <summary>
/// 获取指定用户信息
/// </summary>
/// <param name="openid">用户标识</param>
/// <returns>接口返回值</returns>
public wx_backdata<wx_user_info> GetUserInfo(string openid)
{
string Url = "https://api.weixin.qq.com/cgi-bin/user/info?";
string GetResult = ToolKit.GetData(Url + "access_token=" + this.Accesstoken() + "&openid=" + openid + "&lang=zh_CN");
return GetJson<wx_user_info>(GetResult);
}
#endregion
}
}
View UserList.cshtm
public ActionResult GetUserList(int? page, int? take)
{
List<wx_user_info> Users = new List<wx_user_info>();
var OpenList = new WeChat().GetOpenIdList();
if (OpenList.ResponseState)
{
foreach (var item in OpenList.ResponseData.data.openid)
{
var backdata = new WeChat().GetUserInfo(item);
if (backdata.ResponseState)
{
Users.Add(backdata.ResponseData);
}
}
ViewBag.Tip = OpenList.ResponseData.count + "人";
}
else
{
ViewBag.Tip = "系统异常,编号:" + OpenList.ErrorData.errcode + "错误信息:" + OpenList.ErrorData.errmsg;
}
var PageUseras = Users.Where(ua=>true);
return View(PageUseras);
}
File WeiXin.config
<?xml version="1.0" encoding="utf-8"?>
<weixin>
<appid>wx**********</appid>
<appsecret>*********</appsecret>
<accesstoken>_VqnWkCBEOch4vUgNB7ssBkYIzcsYgW3azkztMLur-OUqKk95U-Sfaqv9XNvGiToAWee2nybxXCtC5x3ipRoT8WotxmM_vZr-WqmD0_XJ9szMZXsqx57EkndVprc1dBtBAQaAFAMLB</accesstoken>
<token>loyung</token>
</weixin>
效果:
后面其他接口及返回,就按照同样的方式添加代码。
C#微信公众号开发-MVC模式公共类封装的更多相关文章
- 线程安全使用(四) [.NET] 简单接入微信公众号开发:实现自动回复 [C#]C#中字符串的操作 自行实现比dotcore/dotnet更方便更高性能的对象二进制序列化 自已动手做高性能消息队列 自行实现高性能MVC WebAPI 面试题随笔 字符串反转
线程安全使用(四) 这是时隔多年第四篇,主要是因为身在东软受内网限制,好多文章就只好发到东软内部网站,懒的发到外面,现在一点点把在东软写的文章给转移出来. 这里主要讲解下CancellationT ...
- VopSdk一个高逼格微信公众号开发SDK:自动化生产(装逼模式开启)
VopSdk一个高逼格微信公众号开发SDK(源码下载) VopSdk一个高逼格微信公众号开发SDK:自动化生产(装逼模式开启) 针对第一版,我们搞了第二版本,老规矩先定个目标. 一 我们的目标 a.移 ...
- C#微信公众号开发系列教程四(接收普通消息)
微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C ...
- VopSdk一个高逼格微信公众号开发SDK(源码下载)
看之前回复很多说明大家很有热情&文章被误删掉了,不想让有的朋友错失这个高逼格的东西,现在重新发布,这次就直接放出源码,文章最末下载地址. 看之前回复很多说明大家很有热情&文章被误删掉了 ...
- 微信公众号开发C#系列-2、微信公众平台接入指南
概述 微信公众平台消息接口的工作原理大概可以这样理解:从用户端到公众号端一个流程是这样的,用户发送消息到微信服务器,微信服务器将接收到的消息post到用户接入时填写的url中,在url处理程序中,首先 ...
- 微信公众号开发系列-13、基于RDIFramework.NET框架整合微信开发应用效果展示
1.前言 通过前面一系列文章的学习,我们对微信公众号开发已经有了一个比较深入和全面的了解. 微信公众号开发为企业解决那些问题呢? 我们经常看到微信公众号定制开发.微信公众平台定制开发,都不知道这些能给 ...
- 微信公众号开发--.net core接入
.net进行微信公众号开发的例子好像比较少,这里做个笔记 首先,我们需要让微信能访问到我们的项目,所以要么需要有一个可以部署项目的连接到公网下的服务器,要么可以通过端口转发将请求转发到我们的项目,总之 ...
- C#微信公众号开发系列教程三(消息体签名及加解密)
http://www.cnblogs.com/zskbll/p/4139039.html C#微信公众号开发系列教程一(调试环境部署) C#微信公众号开发系列教程一(调试环境部署续:vs远程调试) C ...
- C#微信公众号开发系列教程二(新手接入指南)
http://www.cnblogs.com/zskbll/p/4093954.html 此系列前面已经更新了两篇博文了,都是微信开发的前期准备工作,现在切入正题,本篇讲解新手接入的步骤与方法,大神可 ...
随机推荐
- windows docker安装方式的比较小结
稍微小结一下使用InstallDocker 和dockertoolbox的两种方式安装的docker(名称说明可能不妥,仅代表安装方式) InstallDocker 使用的是Microsoft Hy ...
- 自定义控件之 RadioList
var RadioListObj = function (id, url) { this.URL = url;//radiobox source URL this.ID = id;//radioLis ...
- 为speedphp最新版添加 仿Yii 的简易版 数据验证 支持不同场景,自定义回调
给个意见或建议吧 扩展一个Model基类 <?php class BaseModel extends Model{ use ValidationRules; public function ru ...
- 反向Ajax,实现服务器向客户端推送消息
反向Ajax的基本概念是客户端不必从服务器获取信息,服务器会把相关信息直接推送到客户端.这样做的目的是解决Ajax传统Web模型所带来的一个限制:实时信息很难从技术上解决.原因是,客户端必须联系服务器 ...
- 黑马程序员——OC语言 三大特性之继承
Java培训.Android培训.iOS培训..Net培训.期待与您交流! (以下内容是对黑马苹果入学视频的个人知识点总结) 三大特性之继承 (一)继承的基本用法 先建立个Animal再用Dog继承前 ...
- ubuntu auto install update
sudo apt-get update sudo apt-get dist-upgrade 32bit mode sudo dpkg --add-architecture i386
- easyui js基础
$(document).ready( function(){ initload(); });function initConfig(){ //数据列表 yzfymx=$("#tjdj&quo ...
- 11-10 CC150第一章
题目: 1.1 Implement an algorithm to determine if a string has all unique characters. What if you can n ...
- C++虚函数的实现机制示例
C++虚函数的实现机制是通过一个vtable表,指向子类的虚函数地址. 另外,如果不是虚函数,则不能实现用父类引用调用子类方法. #include <windows.h> #include ...
- mouseover 移入某个元素后停留一段时间再执行函授,我用于解决轮播图下面计数用的元素快速移入后会出BUG的问题。
var stop; $(this).bind("mouseover",function(){ stop= setTimeout(function(){ },200); }).bin ...