第一部分:基础配置

第一步:注册微信公众账号

如果开发测试阶段可以打开测试链接地址,注册测试公众号。测试账号除了不能与正式账号通信外其他什么高级接口的都可以实现。

测试号管理地址: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模式公共类封装的更多相关文章

  1. 线程安全使用(四) [.NET] 简单接入微信公众号开发:实现自动回复 [C#]C#中字符串的操作 自行实现比dotcore/dotnet更方便更高性能的对象二进制序列化 自已动手做高性能消息队列 自行实现高性能MVC WebAPI 面试题随笔 字符串反转

    线程安全使用(四)   这是时隔多年第四篇,主要是因为身在东软受内网限制,好多文章就只好发到东软内部网站,懒的发到外面,现在一点点把在东软写的文章给转移出来. 这里主要讲解下CancellationT ...

  2. VopSdk一个高逼格微信公众号开发SDK:自动化生产(装逼模式开启)

    VopSdk一个高逼格微信公众号开发SDK(源码下载) VopSdk一个高逼格微信公众号开发SDK:自动化生产(装逼模式开启) 针对第一版,我们搞了第二版本,老规矩先定个目标. 一 我们的目标 a.移 ...

  3. C#微信公众号开发系列教程四(接收普通消息)

    微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C ...

  4. VopSdk一个高逼格微信公众号开发SDK(源码下载)

    看之前回复很多说明大家很有热情&文章被误删掉了,不想让有的朋友错失这个高逼格的东西,现在重新发布,这次就直接放出源码,文章最末下载地址. 看之前回复很多说明大家很有热情&文章被误删掉了 ...

  5. 微信公众号开发C#系列-2、微信公众平台接入指南

    概述 微信公众平台消息接口的工作原理大概可以这样理解:从用户端到公众号端一个流程是这样的,用户发送消息到微信服务器,微信服务器将接收到的消息post到用户接入时填写的url中,在url处理程序中,首先 ...

  6. 微信公众号开发系列-13、基于RDIFramework.NET框架整合微信开发应用效果展示

    1.前言 通过前面一系列文章的学习,我们对微信公众号开发已经有了一个比较深入和全面的了解. 微信公众号开发为企业解决那些问题呢? 我们经常看到微信公众号定制开发.微信公众平台定制开发,都不知道这些能给 ...

  7. 微信公众号开发--.net core接入

    .net进行微信公众号开发的例子好像比较少,这里做个笔记 首先,我们需要让微信能访问到我们的项目,所以要么需要有一个可以部署项目的连接到公网下的服务器,要么可以通过端口转发将请求转发到我们的项目,总之 ...

  8. C#微信公众号开发系列教程三(消息体签名及加解密)

    http://www.cnblogs.com/zskbll/p/4139039.html C#微信公众号开发系列教程一(调试环境部署) C#微信公众号开发系列教程一(调试环境部署续:vs远程调试) C ...

  9. C#微信公众号开发系列教程二(新手接入指南)

    http://www.cnblogs.com/zskbll/p/4093954.html 此系列前面已经更新了两篇博文了,都是微信开发的前期准备工作,现在切入正题,本篇讲解新手接入的步骤与方法,大神可 ...

随机推荐

  1. 在POM 4中,<dependency>中还引入了<scope>可以使用5个值

     在POM 4中,<dependency>中还引入了<scope>,它主要管理依赖的部署.目前<scope>可以使用5个值: * compile,缺省值,适用于所有 ...

  2. shell脚本参数

    举例说:脚本名称叫test.sh 入参三个: 1 2 3运行test.sh 1 2 3后$*为"1 2 3"(一起被引号包住)$@为"1" "2&qu ...

  3. 响应式注意要添加“视口”约束标记---viewport

    视口:我们试图在iPhone中输出屏幕宽度,你会发现屏幕宽度是980,却和PC屏幕差不多大.原因是苹果主导的这些手机厂商,为了使用户获得完整web体验,很多设备都会欺骗浏览器返回一个数值较大的“视口” ...

  4. 介绍开源的.net通信框架NetworkComms框架之五 心跳检测

    原文网址: http://www.cnblogs.com/csdev Networkcomms 是一款C# 语言编写的TCP/UDP通信框架  作者是英国人  以前是收费的 目前作者已经开源  许可是 ...

  5. iOS开发拓展篇—音频处理(音乐播放器1)

    iOS开发拓展篇—音频处理(音乐播放器1) 说明:该系列文章通过实现一个简单的音乐播放器来介绍音频处理的相关知识点,需要重点注意很多细节的处理. 一.调整项目的结构,导入必要的素材 调整后的项目结构如 ...

  6. Shannon entropy

    Shannon entropy is one of the most important metrics in information theory. Entropy measures the unc ...

  7. JavaScript 语句

    JavaScript 语句 JavaScript 语句向浏览器发出的命令.语句的作用是告诉浏览器该做什么. JavaScript 语句 JavaScript 语句是发给浏览器的命令. 这些命令的作用是 ...

  8. 【个人使用.Net类库】(4)验证码类

    验证码是现在管理系统常用的一种保护用户帐户信息的一种功能. 验证码可以有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登录尝试,虽然这可能是我们登录麻烦一点,但是对用户的密码安全来 ...

  9. Linux驱动之内存映射

    本文参考了http://www.cnblogs.com/geneil/archive/2011/12/08/2281222.html.本文作为学习总结,将主要过程简要描述. 很多驱动实现某些功能都要通 ...

  10. animate.css总结

    本文对animate.css的各个效果进行总结 bounce 从上掉落,在地上小幅度跳起 <!DOCTYPE html> <meta charset="utf-8" ...