C#开发微信
C#开发微信门户及应用教程
C#开发微信门户及应用(1)--开始使用微信接口... 6
1、微信账号... 6
2、微信菜单定义... 7
3、接入微信的链接处理... 8
4、使用开发方式创建菜单... 14
5、我创建的菜单案例... 17
C#开发微信门户及应用(2)--微信消息的处理和应答... 18
1、微信的消息应答交互... 18
2、微信的管理接口... 25
C#开发微信门户及应用(3)--文本消息和图文消息的应答... 29
1、实体信息关系及定义... 30
2、消息的回复处理... 37
C#开发微信门户及应用(4)--关注用户列表及详细信息管理... 41
1、关注用户列表及用户分组信息... 41
2、获取AIP调用者的的Token.. 47
3、获取关注用户列表... 50
4、获取用户详细信息... 59
C#开发微信门户及应用(5)--用户分组信息管理... 62
1、用户分组管理内容... 62
2、用户分组管理接口的实现... 67
3、用户分组接口的调用... 79
C#开发微信门户及应用(6)--微信门户菜单的管理操作... 82
1、菜单的基础信息... 82
2、菜单的实体类定义... 85
3、菜单管理操作的接口实现... 91
C#开发微信门户及应用(7)-微信多客服功能及开发集成... 100
1、多客服准备工作... 101
2、使用多客服客户端或助手操作... 102
3、微信多客服的开发使用... 103
C#开发微信门户及应用(8)-微信门户应用管理系统功能介绍... 108
1、微信菜单管理... 109
2、菜单事件的处理... 112
3、微信消息内容管理... 116
4、应答指令的维护... 121
5、订阅用户管理... 129
6、用户分组管理... 134
7、多媒体管理... 136
8、图文消息处理... 139
9、会话消息管理... 145
10、群发消息管理... 147
C#开发微信门户及应用(9)-微信门户菜单管理及提交到微信服务器... 149
1、微信菜单的要求及相关界面设计... 150
2、提交菜单到微信服务器的操作... 153
C#开发微信门户及应用(10)--在管理系统中同步微信用户分组信息... 160
1、用户分组,在管理系统中的界面设计... 161
2、分组同步操作代码展示... 163
C#开发微信门户及应用(11)--微信菜单的多种表现方式介绍... 172
1、微信自定义菜单的分类... 172
2、重定向类型菜单的URL. 174
3、重定向链接菜单的用途... 182
C#开发微信门户及应用(12)-使用语音处理... 182
1、微信语音接口的定义0. 183
2、语音的处理操作... 186
C#开发微信门户及应用(13)-使用地理位置扩展相关应用... 197
1、微信的地理位置信息... 198
2、地址位置的应用处理... 205
3、地址位置应用扩展... 208
C#开发微信门户及应用(14)-在微信菜单中采用重定向获取用户数据... 223
1、微信重定向菜单的配置... 224
2、脚本转换操作的实现代码... 227
3、重定向页面的设计及处理... 230
C#开发微信门户及应用(15)-微信菜单增加扫一扫、发图片、发地理位置功能... 233
1、微信几个功能的官方介绍... 234
2、微信新菜单功能的测试公众号... 236
3、改进菜单对象和提交菜单... 238
4、微信扫一扫功能集成... 245
5、新菜单功能测试发现的问题... 250
C#开发微信门户及应用(16)-微信企业号的配置和使用... 251
1、微信企业号的注册和登陆... 251
2、设置开发回调模式... 256
3、实现回调页面的功能开发... 259
C#开发微信门户及应用(17)-微信企业号的通讯录管理开发之部门管理... 266
1、企业组织的创建和配置... 266
2、API访问的全局唯一票据AccessToken的获取... 270
2、通讯录管理之部门信息的维护... 272
3、部门管理的API调用... 278
C#开发微信门户及应用(18)-微信企业号的通讯录管理开发之成员管理... 281
1、成员的创建操作... 281
2、成员的更新操作... 287
3、成员的删除、成员的获取、部门成员的获取操作... 290
7、综合例子调用代码... 295
C#开发微信门户及应用(19)-微信企业号的消息发送(文本、图片、文件、语音、视频、图文消息等) 299
1、企业号特点... 299
2、企业号的管理接口内容... 300
3、企业号消息和事件的处理... 302
4、企业号消息管理... 304
5、消息接口的定义和实现... 310
6、消息的发送操作和实际效果... 313
C#开发微信门户及应用(20)-微信企业号的菜单管理... 317
1、菜单的总体介绍... 318
2、菜单的实体类定义和接口定义处理... 319
3、企业号菜单管理接口的调用和处理效果... 324
C#开发微信门户及应用(1)--开始使用微信接口
微信应用如火如荼,很多公司都希望搭上信息快车,这个是一个商机,也是一个技术的方向,因此,有空研究下、学习下微信的相关开发,也就 成为日常计划的重要事情之一了。本系列文章希望从一个循序渐进的角度上,全面介绍微信的相关开发过程和相关经验总结,希望给大家了解一下相关的开发历程。 本随笔主要针对微信开发过程的前期准备和一些初始的工作的介绍。
在写下本文的之前一周时间里,我主要就是参考一些介绍文章以及微信公众平台的相关接口说明,并结合C#的代码开发,整理了自己公司的门 户界面,实现了微信工作号的初步用户交互和信息展示工作,随着工作的进一步开展,越来越多的功能可能加入,并希望从应用角度上扩展微信的接口,从而实现我 对微信接口的技术探秘和了解过程。
1、微信账号
要开发使用微信的平台API,就需要到微信的公众平台(https://mp.weixin.qq.com/)去注册,拥有一个服务号或者订阅号,服务号主要面对企业和组织,订阅号主要面向组织和个人,他们之间有一定的差异,根据不同的需要自己申请对应的账号即可。
为了使用一些高级的接口,你可能需要拥有服务号和高级的认证。账号注册过程,需要下载一个申请表格,打印并盖公章,另外还需要申请人拿着身份证拍照(有点怪异,呵呵),然后上传到服务器进行审核,一般很快就能获取批复。
我以公司名义申请了服务号,账号注册后,会在主界面上显示你的相关信息,另外给你申请一个二维码的东西,扫描二维码即可进入公司的微信关注确认对话框,非常方便。如下就是我申请后的公司账号二维码,可以直接使用扫描。
2、微信菜单定义
微信有两种方式的菜单定义,一种是编辑模式,一种是开发模式,两者互斥,也就是说,一旦我们采用了开发模式,就不能使用编辑模式了,反过来也一样。编辑下的菜单,其实也是可以管理的,但是微信不支持,觉得很不爽。
一般情况下,如果我们刚刚申请了微信号码,可以使用编辑菜单测试一下,根据说明编辑一些菜单试试。虽然微信说24小时内更新,不过一般很快,最快可能一两分钟就更新了,感觉还是不错的。
使用开发者模式,你需要根据微信的要求,在服务器上放置一个页面链接,使用C#开发的,可以采用***.ashx的命名方式,使用Asp.NET的一般处理程序即可,不需要使用普通的页面。
使用开发模式的菜单,也就是可以调用微信API进行菜单创建的工作,对于调用微信的API(微信有很多API可以调用),我们需要知道,有几个参数的重要性,所以在开发模式打开的时候,会给你列出这些参数,如下所示。
3、接入微信的链接处理
上面说了,你申请开发模式对菜单或者对其他API的调用,你需要顺利通过接入微信的测试,也就是确认你填写的链接存在并能顺利经过微信的回调测试。微信提供了一个PHP的页面处理例子,如果我们是C#开发的呢,可以搜一下就会得到答案,我的处理方式如下所示。
创建一个一般处理程序,然后在其处理页面里面增加一个处理逻辑,如果是非POST方式的内容,就是表示微信进行的Get测试,你需要增加一些处理逻辑,把它给你的内容传回去即可,如果是POST方式的,就是微信服务器对接口消息的请求操作了,后面介绍。
///<summary>
/// 微信接口。统一接收并处理信息的入口。
///</summary>
publicclass wxapi : IHttpHandler
{
publicvoid 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);
}
if (!string.IsNullOrEmpty(postString))
{
Execute(postString);
}
}
else
{
Auth(); //微信接入的测试
}
}
一般来说,Auth函数里面,就是要对相关的参数进行获取,然后进行处理返回给微信服务器。
string token = "****";//你申请的时候填写的Token
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"];
完整的Author函数代码如下所示,其中我把业务逻辑进行进一步抽取到了一个新的类里面,方便业务逻辑的管理。
///<summary>
/// 成为开发者的第一步,验证并相应服务器的数据
///</summary>
privatevoid Auth()
{
string token = ConfigurationManager.AppSettings["WeixinToken"];//从配置文件获取Token
if (string.IsNullOrEmpty(token))
{
LogTextHelper.Error(string.Format("WeixinToken 配置项没有配置!"));
}
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 (new BasicApi().CheckSignature(token, signature, timestamp, nonce))
{
if (!string.IsNullOrEmpty(echoString))
{
HttpContext.Current.Response.Write(echoString);
HttpContext.Current.Response.End();
}
}
}
而对微信参数的签名并返回的操作CheckSignature,代码如下所示。
///<summary>
/// 验证微信签名
///</summary>
publicbool CheckSignature(string token, string signature, string timestamp, string nonce)
{
string[] ArrTmp = { token, timestamp, nonce };
Array.Sort(ArrTmp);
string tmpStr = string.Join("", ArrTmp);
tmpStr = FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1");
tmpStr = tmpStr.ToLower();
if (tmpStr == signature)
{
returntrue;
}
else
{
returnfalse;
}
}
4、使用开发方式创建菜单
一旦你顺利通过微信的认证,那么它就让你以开发方式调用它的API,并且可以随意创建你的菜单了。
创建菜单的方式,你可以通过下面的位置进入到他的API处理界面里面。
进入后,你会发现微信把很多消息的处理,分门别类放到不同的分类里面了。
其实我们现在初步要做的就是如何看看,使用代码方式调用创建菜单,进入菜单的API调试界面里面。
你会发现里面还需要输入一个Access_Token的东西,这个是一个会话身份认证,因此你还需要到接口里面去找这个如何创建的。下面图中的两个红色部分,就是我们开始的时候,微信提示我们“开发者凭据”的两个关键参数。
弄完这些,你就可以根据获得的Access_Token进行菜单的创建工作了,根据菜单的定义,它分为几类,可以分为URL方式(View),事件方式(Click)。
click:用户点击click类型按钮后,微信服务器会通过消息接口推送消息类型为event 的结构给开发者(参考消息接口指南),并且带上按钮中开发者填写的key值,开发者可以通过自定义的key值与用户进行交互;
view:用户点击view类型按钮后,微信客户端将会打开开发者在按钮中填写的url值 (即网页链接),达到打开网页的目的,建议与网页授权获取用户基本信息接口结合,获得用户的登入个人信息。
5、我创建的菜单案例
在随笔的开始,我公布了一个二维码,一旦使用微信扫一扫,进行关注服务号后,那么就可以看到我自己创建的菜单了。主菜单一般最多三列,每个主菜单还可以有子菜单,他们的文字都有所限制的。
我们来看看我公司的微信门户菜单,看起来是不是很酷呢。
C#开发微信门户及应用(2)--微信消息的处理和应答
微信应用如火如荼,很多公司都希望搭上信息快车,这个是一个商机,也是一个技术的方向,因此,有空研究下、学习下微信的相关开发,也就 成为计划的安排事情之一了。本系列文章希望从一个循序渐进的角度上,全面介绍微信的相关开发过程和相关经验总结,希望给大家了解一下相关的开发历程。本篇 随笔主要基于上一篇《C#开发微信门户及应用(1)--开始使用微信接口》的基础上进行深入的介绍,介绍微信消息的处理和应答的过程。
1、微信的消息应答交互
我们知道,微信的服务器架起了客户手机和开发者服务器的一个桥梁,通过消息的传递和响应,实现了与用户的交互操作,下面是它的消息流程图。
微信向开发者服务器请求的消息包含了多种类型,不过基本来说,分为了文本消息处理、事件消息处理、语音消息的识别,以及成为开发者之前的那个消息认证操作基本分类,下面是我绘制的一个消息分类图,其中介绍了这几种关系,以及各自的消息细化分类。
对于这些消息的请求,我们在开发服务器端,需要编写相关的逻辑进行对应给的处理,然后给微信服务器平台回应消息即可。
在前一篇的随笔里面我贴过代码,介绍微信消息处理的入口操作,代码如下所示。
publicvoid ProcessRequest(HttpContext context)
{
//WHC.Framework.Commons.LogTextHelper.Info("测试记录");
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);
}
if (!string.IsNullOrEmpty(postString))
{
Execute(postString);
}
}
else
{
Auth();
}
}
其中的Execute(postString);就是对消息的处理函数,它实现了对不同消息的分发处理过程。‘
///<summary>
/// 处理各种请求信息并应答(通过POST的请求)
///</summary>
///<param name="postStr">POST方式提交的数据</param>
privatevoid Execute(string postStr)
{
WeixinApiDispatch dispatch = new WeixinApiDispatch();
string responseContent = dispatch.Execute(postStr);
HttpContext.Current.Response.ContentEncoding = Encoding.UTF8;
HttpContext.Current.Response.Write(responseContent);
}
里面的WeixinApiDispatch就是一个分发的管理类,它提取请求消息的内容,并构建不同类型的消息参数,传递给不同的响应函数进行处理,然后返回封装好的XML内容,作为响应。
具体的代码处理逻辑如下图所示。
这个消息处理接口,其实就是定义好一系列的对请求消息的处理操作,参数是不同给的消息对象,具体的代码定义如下所示(由于篇幅原因,省略部分接口,具体可以参考上图)。
///<summary>
/// 客户端请求的数据接口
///</summary>
publicinterface IWeixinAction
{
///<summary>
/// 对文本请求信息进行处理
///</summary>
///<param name="info">文本信息实体</param>
///<returns></returns>
string HandleText(RequestText info);
///<summary>
/// 对图片请求信息进行处理
///</summary>
///<param name="info">图片信息实体</param>
///<returns></returns>
string HandleImage(RequestImage info);
...........................
///<summary>
/// 对订阅请求事件进行处理
///</summary>
///<param name="info">订阅请求事件信息实体</param>
///<returns></returns>
string HandleEventSubscribe(RequestEventSubscribe info);
///<summary>
/// 对菜单单击请求事件进行处理
///</summary>
///<param name="info">菜单单击请求事件信息实体</param>
///<returns></returns>
string HandleEventClick(RequestEventClick info);
..............................
}
从上面的代码可以看出,不同的消息,到处理函数这里,就以不同的消息实体类的方式传递过来了(注意:实体类是我根据程序开发需要自己定义的,非微信本身的实体类),这样非常方便我们处理操作,否则每次需要解析不同的消息内容,很容易出现问题,这样强类型的数据类型,提高了我们开发微信应用的强壮型和高效性。这些实体类的对象有一定的继承关系的,他们的继承关系如下所示。
2、微信的管理接口
上面的消息分类是微信服务器向开发者服务器发送的消息请求操作,还有一种消息,是我们开发者服务器向微信服务器进行的消息请求或者响应,这种这里暂且称之为微信的管理接口,它表明了我们可以通过这些接口进行相关的消息回复或者数据管理操作。它的分类图如下所示。
微信的回复消息处理,它也和上面小节的信息一样,它也是继承自BaseMessage实体类的(同样,下图的实体类及其继承关系也是自定义的,方便程序开发),它的关系如下所示
回复的消息,一般用的最多的是文本消息和图文消息。
文本消息的效果如下所示。
图文消息,可以增加图片,还可以增加详细的链接页面,是非常好看的一种效果,对于一些内容比较多,希望展现更好效果的,一般采用这种,效果如下所示。
C#开发微信门户及应用(3)--文本消息和图文消息的应答
微信应用如火如荼,很多公司都希望搭上信息快车,这个是一个商机,也是一个技术的方向,因此,有空研究下、学习下微信的相关开发,也就 成为计划的安排事情之一了。本系列文章希望从一个循序渐进的角度上,全面介绍微信的相关开发过程和相关经验总结,希望给大家了解一下相关的开发历程。
在前面两篇两篇随笔《C#开发微信门户及应用(1)--开始使用微信接口》和《C#开发微信门户及应用(2)--微信消息的处理和应答》里面,大致介绍了我微信应用的框架构建,本随笔继续介绍这一主题,介绍消息应答里面的文本应答和图文应答的过程。
我们知道,给手机用户发送响应消息,它可以分为好多种方式,如回复文本消息、回复图片消息、回复语音消息、回复视频消息、回复音乐消息、回复图文消息等,如下所示。
而其中图片、视频、语音这三种方式,是需要开通微信认证才可以向用户发送存在微信服务器上的媒体信息,一般没有认证的公众号或者服务号,是不能发送这几种内容的。
1、实体信息关系及定义
在上一篇微信开发的随笔中,我展示了对接收消息和回复消息的应用实体类,这些实体类是我根据需要,根据开发需要,在应用层面对它们进行了封装,如回复的消息关系如下所示。
消息基类BaseMessage的实体类定义如下所示,它对日期构造了一个整形数值,并具备了一些常规的属性,并且还有一个重要的ToXML方法,用来给方法传递这些XML数据的。
///<summary>
/// 基础消息内容
///</summary>
[XmlRoot(ElementName = "xml")]
publicclass BaseMessage
{
///<summary>
/// 初始化一些内容,如创建时间为整形,
///</summary>
public BaseMessage()
{
this.CreateTime = DateTime.Now.DateTimeToInt();
}
///<summary>
/// 开发者微信号
///</summary>
publicstring ToUserName { get; set; }
///<summary>
/// 发送方帐号(一个OpenID)
///</summary>
publicstring FromUserName { get; set; }
///<summary>
/// 消息创建时间 (整型)
///</summary>
publicint CreateTime { get; set; }
///<summary>
/// 消息类型
///</summary>
publicstring MsgType { get; set; }
publicvirtualstring ToXml()
{
this.CreateTime = DateTime.Now.DateTimeToInt();//重新更新
return MyXmlHelper.ObjectToXml(this);
}
}
回复的文本消息实体类代码如下所示,我们可以看到,它继承了很多通用的实体属性,并且还具备了一个ToXml的通用方法,我们需要把它转换为响应的XML的时候,就使用这个方法就可以了。
///<summary>
/// 回复文本消息
///</summary>
[System.Xml.Serialization.XmlRoot(ElementName = "xml")]
publicclass ResponseText : BaseMessage
{
public ResponseText()
{
this.MsgType = ResponseMsgType.Text.ToString().ToLower();
}
public ResponseText(BaseMessage info) : this()
{
this.FromUserName = info.ToUserName;
this.ToUserName = info.FromUserName;
}
///<summary>
/// 内容
///</summary>
publicstring Content { get; set; }
}
而图文消息对象类ResponseNews,它包含更多的信息定义
///<summary>
/// 回复图文消息
///</summary>
[System.Xml.Serialization.XmlRoot(ElementName = "xml")]
publicclass ResponseNews : BaseMessage
{
public ResponseNews()
{
this.MsgType = ResponseMsgType.News.ToString().ToLower();
this.Articles = new List<ArticleEntity>();
}
public ResponseNews(BaseMessage info) : this()
{
this.FromUserName = info.ToUserName;
this.ToUserName = info.FromUserName;
}
///<summary>
/// 图文消息个数,限制为10条以内
///</summary>
publicint ArticleCount
{
get
{
returnthis.Articles.Count;
}
set
{
;//增加这个步骤才出来XML内容
}
}
///<summary>
/// 图文列表。
/// 多条图文消息信息,默认第一个item为大图,注意,如果图文数超过10,则将会无响应
///</summary>
[System.Xml.Serialization.XmlArrayItem("item")]
public List<ArticleEntity> Articles { get; set; }
}
而其中的图文列表集合中的对象,它也是一个实体类型,包含了一些图文的链接,标题等信息,不在赘述。
2、消息的回复处理
如对于文本消息,我们可以用以下的方式进行处理。
ResponseText response = new ResponseText(info);
response.Content = "抱歉,此功能暂未开通。";
result = response.ToXml();
对于图文消息,我们可能需要录入更多的消息才能返回更好的效果。
注意图文的消息,图片的尺寸最好按照官方的标准,否则在手机上看起来不好看,官方的标准好像是宽高是(360,200)像素
///<summary>
/// 订阅或者显示公司信息
///</summary>
///<param name="info"></param>
///<returns></returns>
privatestring ShowCompanyInfo(BaseMessage info)
{
string result = "";
//使用在微信平台上的图文信息(单图文信息)
ResponseNews response = new ResponseNews(info);
ArticleEntity entity = new ArticleEntity();
entity.Title = "广州爱奇迪软件科技有限公司";
entity.Description = "欢迎关注广州爱奇迪软件--专业的单位信息化软件和软件开发框架提供商,我们立志于为客户提供最好的软件及服务。\r\n";
entity.Description += "我们是一家极富创新性的软件科技公司,从事研究、开发并销售最可靠的、安全易用的技术产品及优质专业的服务,帮助全球客户和合作伙伴取得成功。\r\n......(此处省略1000字,哈哈)";
entity.PicUrl = "http://www.iqidi.com/WeixinImage/company.png";
entity.Url = "http://www.iqidi.com";
response.Articles.Add(entity);
result = response.ToXml();
return result;
}
我们来看看我公司的微信门户菜单,看起来是不是很酷呢。
对于这两种(文本消息、图文消息)用的地方是最多,很多微信门户,都主要是使用这两种方式进行响应。当然,我们还可以根据客户手机提交上来的各种消息进行不同的处理,请求消息的类型我在上一篇的随笔有介绍,如下所示。
需要关注了解整体效果,可以使用微信直接扫描二维码即可。
C#开发微信门户及应用(4)--关注用户列表及详细信息管理
在上个月的对C#开发微信门户及应用做了介绍,写过了几篇的随笔进行分享,由于时间关系,间隔了一段时间没有继续写这个系列的博客了,并不是对这个方面停止了研究,而是继续深入探索这方面的技术,为了更好的应用起来,专心做好底层的技术开发。
微信的很重要的一个特点就是能够利用其平台庞大的用户群体,因此很容易整合在CRM(客户关系管理)系统里面,服务号和订阅好都能够向关注者推送相 关的产品消息,还能和48小时内响应消息和事件的活跃用户进行交互对话,因此用户信息是微信API里面非常重要的一环,本随笔主要介绍获取关注用户、查看 用户信息、分组管理等方面的开发应用。
1、关注用户列表及用户分组信息
在微信的管理平台上,我们可以看到自己账号的关注者用户,以及用户分组信息,如下所示。
上面的管理界面,能看到关注者用户的基础信息,但是使用微信API获取到的是一个称之为OpenID的列表,我们先了解这个东西是什么?微信API的说明给出下面的解析:
关注者列表由一串OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的。对于不同公众号,同一用户的openid不同)组成。公众号可通过本接口来根据OpenID获取用户基本信息,包括昵称、头像、性别、所在城市、语言和关注时间。
上面的解析意思很清楚了,就是一个用户关注我们的公众号,那么不管他是第几次关注,对我们公众号来说,都是一个确定的值;但是,一个用户对其他公众号,却有着其他不同的OpenID。
微信提供了为数不多的几个关键字信息,用来记录用户的相关内容,根据用户的相关定义,我们定义一个实体类,用来放置获取回来的用户信息。
///<summary>
/// 高级接口获取的用户信息。
/// 在关注者与公众号产生消息交互后,公众号可获得关注者的OpenID
/// (加密后的微信号,每个用户对每个公众号的OpenID是唯一的。对于不同公众号,同一用户的openid不同)。
/// 公众号可通过本接口来根据OpenID获取用户基本信息,包括昵称、头像、性别、所在城市、语言和关注时间。
///</summary>
publicclass UserJson : BaseJsonResult
{
///<summary>
/// 用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息。
///</summary>
publicint subscribe { get; set; }
///<summary>
/// 用户的标识,对当前公众号唯一
///</summary>
publicstring openid { get; set; }
///<summary>
/// 用户的昵称
///</summary>
publicstring nickname { get; set; }
///<summary>
/// 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
///</summary>
publicint sex { get; set; }
///<summary>
/// 用户的语言,简体中文为zh_CN
///</summary>
publicstring language { get; set; }
///<summary>
/// 用户所在城市
///</summary>
publicstring city { get; set; }
///<summary>
/// 用户所在省份
///</summary>
publicstring province { get; set; }
///<summary>
/// 用户所在国家
///</summary>
publicstring country { get; set; }
///<summary>
/// 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空
///</summary>
publicstring headimgurl { get; set; }
///<summary>
/// 用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间
///</summary>
publiclong subscribe_time { get; set; }
}
根据分组信息定义,我们定义一个分组的实体类信息。
///<summary>
/// 分组信息
///</summary>
publicclass GroupJson : BaseJsonResult
{
///<summary>
/// 分组id,由微信分配
///</summary>
publicint id { get; set; }
///<summary>
/// 分组名字,UTF8编码
///</summary>
publicstring name { get; set; }
}
2、获取AIP调用者的的Token
在做微信API的开发,很多时候,我们都需要传入一个AccessToken,这个就是区分调用者和记录会话信息的字符串,因此,在学习所有API开发之前,我们需要很好理解这个访问控制参数。
这个对象的定义,我们可以从微信的API说明中了解。
access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token。正常情况下access_token有效期为7200秒,重复获取将导致上次获取的access_token失效。由于获取access_token的api调用次数非常有限,建议开发者全局存储与更新access_token,频繁刷新access_token会导致api调用受限,影响自身业务。
根据上面的说明定义,我们可以看到,它是一个和身份,以及会话时间有关的一个参数,而且它的产生次数有限制,因此要求我们需要对它进行缓存并重复利用,在会话到期之前,我们应该尽可能重用这个参数,避免反复请求,增加服务器压力,以及调用的时间。
我定义了一个方法,用来构造生成相关的Access Token,而且它具有缓存的功能,但具体如何缓存及使用,对我API的调用是透明的,我们只要用的时候,就对它调用就是了。
/// 获取凭证接口
///</summary>
///<param name="appid">第三方用户唯一凭证</param>
///<param name="secret">第三方用户唯一凭证密钥,既appsecret</param>
string GetAccessToken(string appid, string secret);
缓存主要是基于.NET4增加的类库MemoryCache,这个是一个非常不错的缓存类。
我的获取AccessToken的操作实现代码如下所示。
///<summary>
/// 获取每次操作微信API的Token访问令牌
///</summary>
///<param name="appid">应用ID</param>
///<param name="secret">开发者凭据</param>
///<returns></returns>
publicstring GetAccessToken(string appid, string secret)
{
//正常情况下access_token有效期为7200秒,这里使用缓存设置短于这个时间即可
string access_token = MemoryCacheHelper.GetCacheItem<string>("access_token", delegate()
{
string grant_type = "client_credential";
var url = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type={0}&appid={1}&secret={2}",
grant_type, appid, secret);
HttpHelper helper = new HttpHelper();
string result = helper.GetHtml(url);
string regex = "\"access_token\":\"(?<token>.*?)\"";
string token = CRegex.GetText(result, regex, "token");
return token;
},
new TimeSpan(0, 0, 7000)//7000秒过期
);
return access_token;
}
由于我们知道,AccessToken默认是7200秒过期,因此在这个时间段里面,我们尽可能使用缓存来记录它的值,如果超过了这个时间,我们调用这个方法的时候,它会自动重新获取一个新的值给我们了。
3、获取关注用户列表
获取关注用户列表,一次拉取API调用,最多拉取10000个关注者的OpenID,可以通过多次拉取的方式来满足需求。微信的接口定义如下所示。
http请求方式: GET(请使用https协议)
https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID
这个接口返回的数据是
{"total":2,"count":2,"data":{"openid":["","OPENID1","OPENID2"]},"next_openid":"NEXT_OPENID"}
根据返回的Json数据定义,我们还需要定义两个实体类,用来存放返回的结果。
///<summary>
/// 获取关注用户列表的Json结果
///</summary>
publicclass UserListJsonResult : BaseJsonResult
{
///<summary>
/// 关注该公众账号的总用户数
///</summary>
publicint total { get; set; }
///<summary>
/// 拉取的OPENID个数,最大值为10000
///</summary>
publicint count { get; set; }
///<summary>
/// 列表数据,OPENID的列表
///</summary>
public OpenIdListData data { get; set; }
///<summary>
/// 拉取列表的后一个用户的OPENID
///</summary>
publicstring next_openid { get; set; }
}
///<summary>
/// 列表数据,OPENID的列表
///</summary>
publicclass OpenIdListData
{
///<summary>
/// OPENID的列表
///</summary>
public List<string> openid { get; set; }
}
为了获取相关的用户信息,我定义了一个接口,用来获取用户的信息,接口定义如下所示。
///<summary>
/// 微信用户管理的API接口
///</summary>
publicinterface IUserApi
{
///<summary>
/// 获取关注用户列表
///</summary>
///<param name="accessToken">调用接口凭证</param>
///<param name="nextOpenId">第一个拉取的OPENID,不填默认从头开始拉取</param>
///<returns></returns>
List<string> GetUserList(string accessToken, string nextOpenId = null);
///<summary>
/// 获取用户基本信息
///</summary>
///<param name="accessToken">调用接口凭证</param>
///<param name="openId">普通用户的标识,对当前公众号唯一</param>
///<param name="lang">返回国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语</param>
UserJson GetUserDetail(string accessToken, string openId, Language lang = Language.zh_CN);
然后在实现类里面,我们分别对上面两个接口进行实现,获取用户列表信息如下所示。
///<summary>
/// 获取关注用户列表
///</summary>
///<param name="accessToken">调用接口凭证</param>
///<param name="nextOpenId">第一个拉取的OPENID,不填默认从头开始拉取</param>
///<returns></returns>
public List<string> GetUserList(string accessToken, string nextOpenId = null)
{
List<string> list = new List<string>();
string url = string.Format("https://api.weixin.qq.com/cgi-bin/user/get?access_token={0}", accessToken);
if (!string.IsNullOrEmpty(nextOpenId))
{
url += "&next_openid=" + nextOpenId;
}
UserListJsonResult result = JsonHelper<UserListJsonResult>.ConvertJson(url);
if (result != null&& result.data != null)
{
list.AddRange(result.data.openid);
}
return list;
}
我们看到,转换的逻辑已经放到了JsonHelper里面去了,这个辅助类里面分别对数值进行了获取内容,验证返回值,然后转换正确实体类几个部分的操作。
获取内容,通过辅助类HttpHelper进行,这个在我的公用类库里面,里面的逻辑主要就是通过HttpRequest进行数据的获取操作,不在赘述。
HttpHelper helper = new HttpHelper();
string content = helper.GetHtml(url);
由于返回的内容,我们需要判断它是否正确返回所需的结果,如果没有,抛出自定义的相关异常,方便处理,具体如下所示。
///<summary>
/// 检查返回的记录,如果返回没有错误,或者结果提示成功,则不抛出异常
///</summary>
///<param name="content">返回的结果</param>
///<returns></returns>
privatestaticbool VerifyErrorCode(string content)
{
if (content.Contains("errcode"))
{
ErrorJsonResult errorResult = JsonConvert.DeserializeObject<ErrorJsonResult>(content);
//非成功操作才记录异常,因为有些操作是返回正常的结果({"errcode": 0, "errmsg": "ok"})
if (errorResult != null&& errorResult.errcode != ReturnCode.请求成功)
{
string error = string.Format("微信请求发生错误!错误代码:{0},说明:{1}", (int)errorResult.errcode, errorResult.errmsg);
LogTextHelper.Error(errorResult);
thrownew WeixinException(error);//抛出错误
}
}
returntrue;
}
然后转换为相应的格式,就是通过Json.NET的类库进行转换。
T result = JsonConvert.DeserializeObject<T>(content);
return result;
这样我们就可以在ConvertJson函数实体里面,完整的进行处理和转换了,转换完整的函数代码如下所示。
///<summary>
/// Json字符串操作辅助类
///</summary>
publicclass JsonHelper<T>where T : class, new()
{
///<summary>
/// 检查返回的记录,如果返回没有错误,或者结果提示成功,则不抛出异常
///</summary>
///<param name="content">返回的结果</param>
///<returns></returns>
privatestaticbool VerifyErrorCode(string content)
{
if (content.Contains("errcode"))
{
ErrorJsonResult errorResult = JsonConvert.DeserializeObject<ErrorJsonResult>(content);
//非成功操作才记录异常,因为有些操作是返回正常的结果({"errcode": 0, "errmsg": "ok"})
if (errorResult != null&& errorResult.errcode != ReturnCode.请求成功)
{
string error = string.Format("微信请求发生错误!错误代码:{0},说明:{1}", (int)errorResult.errcode, errorResult.errmsg);
LogTextHelper.Error(errorResult);
thrownew WeixinException(error);//抛出错误
}
}
returntrue;
}
///<summary>
/// 转换Json字符串到具体的对象
///</summary>
///<param name="url">返回Json数据的链接地址</param>
///<returns></returns>
publicstatic T ConvertJson(string url)
{
HttpHelper helper = new HttpHelper();
string content = helper.GetHtml(url);
VerifyErrorCode(content);
T result = JsonConvert.DeserializeObject<T>(content);
return result;
}
}
调用这个API的界面层代码如下所示(测试代码)
IUserApi userBLL = new UserApi();
List<string> userList = userBLL.GetUserList(token)
4、获取用户详细信息
上面的获取列表操作,相对比较简单,而且不用POST任何数据,因此通过Get协议就能获取到所需的数据。
本小节继续介绍获取用户详细信息的操作,这个操作也是通过GET协议就可以完成的。
这个API的调用定义如下所示:
http请求方式: GET
https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
请发表评论