2023年2月

在本系列随笔的前面,主要就是介绍微信公众号的门户应用开发,最近把整个微信框架进行了扩展补充,增加了最新的企业号的API封装和开发,后续主要介绍如何利用C#进行微信企业号的开发工作,本篇作为微信企业号的开发的起步篇,介绍微信企业号的配置和使用。

1、微信企业号的注册和登陆

企业号是继公众号、订阅号的另外一种微信类型,它主要是面对企业的。企业号是微信为企业客户提供的移动应用入口。可以帮助企业建立员工、上下游供应链与企业 IT 系统间的连接。利用 企业号 ,企业或第三方合作伙伴可以帮助企业快速、低成本的实现高质量的移动轻应用,实现生产、管理、协作、运营的 移动化 。

个人觉得企业号最大的亮点是可以不限数量的消息发送,也就是可以在企业员工之间畅通交流。相对于公众号和订阅号,发送消息的谨慎程度,微信企业号可谓给人眼前一亮的感觉。不过微信企业号是需要内部建立好通讯录,关注者需要匹配通讯录的微信号、邮箱、电话号码任一个通过才可以关注,也就是可以防止其他外来人员的自由关注了,另外如果为了安全考虑,还可以设置二次验证,也就是一个审核过程。

企业号的认证和公众号一样,需要提供相关的企业资质文件,并且认证每年都要收取费用,否则可能有人员和功能的一些限制。觉得微信真是想着方法赚钱,目前已有的收费模式有,订阅号、公众号、企业号、开放平台,好像都有认证收费的了,而且微信小店也还需要收2万的押金,一切都是钱呀。

好了,其他不多说,微信的注册地址是:https://qy.weixin.qq.com,一个邮箱不能同时注册微信公众号和微信企业号。

对于企业开通企业号并开始使用需要四步

1) 企业到微信官网( http://qy.weixin.qq.com )申请开通;

2) 开通后,企业在企业号管理后台导入成员,发布二维码;

3) 企业调用企业号 api 与企业自有系统对接开发;

4) 员工关注,收到微信信息,在微信中与企业交互

注册好企业号,就可以通过微信扫一扫,扫描企业二维码进行登录了,扫描的时候,需要微信进行确认,才可以继续输入密码进行登录,操作界面如下所示(左边是手机截图,右边是网页截图)。


登录后我们就可以看到对应的电脑端的管理界面了。

2、设置开发回调模式

如果开发过微信公众号,那么我们就知道,如果需要在微信服务器和网站服务器之间建立连接关系,实现消息的转发和处理,那么就应该设置一个回调模式,需要配置好相关的参数。然后在自己 网站服务器里面建立一个处理微信服务器消息的入口。

进入配置后,我们需要修改相关的URL、Token、EncodingAESKey等参数,主要是URL,这个就是和公众号的入口处理一样的,需要我们发布到网站服务器上的处理入口。

Token和AESKey可以根据提示动态生成一个即可,AESKey好像必须是23位的,所以这个一般是让它自己生成的,这个主要用来加密解密使用的。

URL、Token、EncodingAESKey三个参数说明。

1)URL是企业应用接收企业号推送请求的访问协议和地址,支持http或https协议。

2)Token可由企业任意填写,用于生成签名。

3)EncodingAESKey用于消息体的加密,是AES密钥的Base64编码。

验证URL、Token以及加密的详细处理请参考后续 “接收消息时的加解密处理” 的部分。

我公司的企业号配置后的界面如下所示。

这个URL里面指向的页面功能,需要对数据进行解析并返回给微信服务器,因此我们需要在服务器上预先部署好这个处理功能入口。

除了上面的几个函数,还有一个CorpID的参数需要使用,我们可以在后台主界面-设置里面查看到。

然后我们为了方便网站后台使用,我们和公众号的配置一样,把它放到了Web.Config里面,如下所示。

3、实现回调页面的功能开发

前面介绍了几个配置项,需要在回调页面里面使用的,本小节继续介绍如何实现企业号信息的回发,使之通过回调测试的操作。

由于回调测试的数据是通过Get方式发送的,因此我们的处理逻辑代码如下所示,和公众号的类似处理,只是实现部分不太一样而已。

    /// <summary>
    ///企业号回调信息接口。统一接收并处理信息的入口。/// </summary>
    public classcorpapi : IHttpHandler
{
/// <summary> ///处理企业号的信息/// </summary> /// <param name="context"></param> public voidProcessRequest(HttpContext context)
{
string postString = string.Empty;if (HttpContext.Current.Request.HttpMethod.ToUpper() == "POST")
{
using (Stream stream =HttpContext.Current.Request.InputStream)
{
Byte[] postBytes
= newByte[stream.Length];
stream.Read(postBytes,
0, (Int32)stream.Length);
postString
=Encoding.UTF8.GetString(postBytes);
}
if (!string.IsNullOrEmpty(postString))
{
Execute(postString);
}
}
else{
Auth();
}
}
/// <summary> ///成为开发者的第一步,验证并相应服务器的数据/// </summary> private voidAuth()
{
#region 获取关键参数 string token = ConfigurationManager.AppSettings["CorpToken"];//从配置文件获取Token if (string.IsNullOrEmpty(token))
{
LogTextHelper.Error(
string.Format("CorpToken 配置项没有配置!"));
}
string encodingAESKey = ConfigurationManager.AppSettings["EncodingAESKey"];//从配置文件获取EncodingAESKey if (string.IsNullOrEmpty(encodingAESKey))
{
LogTextHelper.Error(
string.Format("EncodingAESKey 配置项没有配置!"));
}
string corpId = ConfigurationManager.AppSettings["CorpId"];//从配置文件获取corpId if (string.IsNullOrEmpty(corpId))
{
LogTextHelper.Error(
string.Format("CorpId 配置项没有配置!"));
}
#endregion string echoString = HttpContext.Current.Request.QueryString["echoStr"];string signature = HttpContext.Current.Request.QueryString["msg_signature"];//企业号的 msg_signature string timestamp = HttpContext.Current.Request.QueryString["timestamp"];string nonce = HttpContext.Current.Request.QueryString["nonce"];string decryptEchoString = "";if (new CorpBasicApi().CheckSignature(token, signature, timestamp, nonce, corpId, encodingAESKey, echoString, refdecryptEchoString))
{
if (!string.IsNullOrEmpty(decryptEchoString))
{
HttpContext.Current.Response.Write(decryptEchoString);
HttpContext.Current.Response.End();
}
}
}

具体的处理代码如下所示,里面的一个加解密处理的类是微信企业号附录里面提供的,我使用了C#版本的SDK而已。

    /// <summary>
    ///企业号基础操作API实现/// </summary>
    public classCorpBasicApi : ICorpBasicApi
{
/// <summary> ///验证企业号签名/// </summary> /// <param name="token">企业号配置的Token</param> /// <param name="signature">签名内容</param> /// <param name="timestamp">时间戳</param> /// <param name="nonce">nonce参数</param> /// <param name="corpId">企业号ID标识</param> /// <param name="encodingAESKey">加密键</param> /// <param name="echostr">内容字符串</param> /// <param name="retEchostr">返回的字符串</param> /// <returns></returns> public bool CheckSignature(string token, string signature, string timestamp, string nonce, string corpId, string encodingAESKey, string echostr, ref stringretEchostr)
{
WXBizMsgCrypt wxcpt
= newWXBizMsgCrypt(token, encodingAESKey, corpId);int result = wxcpt.VerifyURL(signature, timestamp, nonce, echostr, refretEchostr);if (result != 0)
{
LogTextHelper.Error(
"ERR: VerifyURL fail, ret:" +result);return false;
}
return true;//ret==0表示验证成功,retEchostr参数表示明文,用户需要将retEchostr作为get请求的返回参数,返回给企业号。//HttpUtils.SetResponse(retEchostr); }

如果对这个《C#开发微信门户及应用》系列感兴趣,可以关注我的其他文章,系列随笔如下所示:

C#开发微信门户及应用(25)-微信企业号的客户端管理功能

C#开发微信门户及应用(24)-微信小店货架信息管理

C#开发微信门户及应用(23)-微信小店商品管理接口的封装和测试

C#开发微信门户及应用(22)-微信小店的开发和使用

C#开发微信门户及应用(21)-微信企业号的消息和事件的接收处理及解密

C#开发微信门户及应用(20)-微信企业号的菜单管理

C#开发微信门户及应用(19)-微信企业号的消息发送(文本、图片、文件、语音、视频、图文消息等)

C#开发微信门户及应用(18)-微信企业号的通讯录管理开发之成员管理

C#开发微信门户及应用(17)-微信企业号的通讯录管理开发之部门管理

C#开发微信门户及应用(16)-微信企业号的配置和使用

C#开发微信门户及应用(15)-微信菜单增加扫一扫、发图片、发地理位置功能

C#开发微信门户及应用(14)-在微信菜单中采用重定向获取用户数据

C#开发微信门户及应用(13)-使用地理位置扩展相关应用

C#开发微信门户及应用(12)-使用语音处理

C#开发微信门户及应用(11)--微信菜单的多种表现方式介绍

C#开发微信门户及应用(10)--在管理系统中同步微信用户分组信息

C#开发微信门户及应用(9)-微信门户菜单管理及提交到微信服务器

C#开发微信门户及应用(8)-微信门户应用管理系统功能介绍

C#开发微信门户及应用(7)-微信多客服功能及开发集成

C#开发微信门户及应用(6)--微信门户菜单的管理操作

C#开发微信门户及应用(5)--用户分组信息管理

C#开发微信门户及应用(4)--关注用户列表及详细信息管理

C#开发微信门户及应用(3)--文本消息和图文消息的应答


C#开发微信门户及应用(2)--微信消息的处理和应答


C#开发微信门户及应用(1)--开始使用微信接口

前面一篇随笔企业号的一些基础信息,以及介绍如何配置企业号的回调方式实现和企业号服务器进行沟通的桥梁。本篇主要还是继续介绍企业号的开发工作的开展,介绍微信企业号通讯录管理开发功能,介绍其中组织机构里面如何获取和管理部门的信息等内容。

1、企业组织的创建和配置

首先我们可以在企业号的管理后台里面创建一个组织机构,里面创建一些部门和人员列表,方便我们开发和使用。

例如创建一个广州爱奇迪的根结构,然后在其中在创建一些组织机构,如下图所示。

然后给组织结构根节点“广州爱奇迪”增加一个管理员权限,以后再开发接口里面也就可以使用这个管理员所属的权限Secret值进行调用了。

CorpID是企业号的标识,每个企业号拥有一个唯一的CorpID;Secret是管理组凭证密钥。
系统管理员可通过管理端的权限管理功能创建管理组,分配管理组对应用、通讯录、接口的访问权限。完成后,管理组即可获得唯一的secret。系统管理员可通过权限管理查看所有管理组的secret,其他管理员可通过设置中的开发者凭据查看。

我的企业号的创建者和“广州爱奇迪”组织结构的管理员是不同的,由于Secret是管理组凭证密钥,因此管理者负责不同的组织机构管理的话,自己的管理Secret值可能就不同了。如果我们需要调用接口,就需要用到这个属于自己权限级别的Secret值,如下图所示。

如果不是企业号的创建者,那么可能不能修改里面的一些权限分配,只能查看。

2、API访问的全局唯一票据AccessToken的获取

和公众号一样,我们调用企业号API的第一步也是需要先获取访问的票据AccessToken。这个票据是全局性的,有一定的时效和频率控制,因此需要适当的进行缓存,不能每次调用都去刷新获取。

企业号获取访问票据的主要的逻辑代码如下所示,其主要的就是需要使用管理者的Secret值去获取对应的口令,这样它就能够知道管理的是那个组织结构的了。

        /// <summary>
        ///获取每次操作微信API的Token访问令牌/// </summary>
        /// <param name="corpid">企业Id</param>
        /// <param name="corpsecret">管理组的凭证密钥</param>
        /// <returns></returns>
        public string GetAccessTokenNoCache(string corpid, stringcorpsecret)
{
var url = string.Format("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={0}&corpsecret={1}",
corpid, corpsecret);

HttpHelper helper
= newHttpHelper();string result =helper.GetHtml(url);string regex = "\"access_token\":\"(?<token>.*?)\"";string token = CRegex.GetText(result, regex, "token");returntoken;
}

微信企业号的说明如下所示:

当企业应用调用企业号接口时,企业号后台为根据此次访问的AccessToken,校验访问的合法性以及所对应的管理组的管理权限以返回相应的结果。

注:
你应该审慎配置管理组的权限,够用即好,权限过大会增加误操作可能性及信息安全隐患。

AccessToken是企业号的全局唯一票据,调用接口时需携带AccessToken。AccessToken需要用
CorpID

Secret
来换取,不同的Secret会返回不同的AccessToken。
正常情况下AccessToken有效期为7200秒,有效期内重复获取返回相同结果,并自动续期。由于获取access_token的api调用次数非常有限,建议企业全局存储与更新access_token,频繁刷新access_token会导致api调用受限,影响自身业务

2、通讯录管理之部门信息的维护

有了第一节里面的访问票据,我们就可以利用API来做很多事情了,包括组织结构的获取、创建、删除等等功能。

创建部门的官方接口定义如下所示。

  • 请求说明

Https请求方式: POST

https://qyapi.weixin.qq.com/cgi-bin/department/create?access_token=ACCESS_TOKEN

请求包结构体为:

{
   "name": "邮箱产品组",
   "parentid": "1"
}
  • 参数说明
参数 必须 说明
access_token 调用接口凭证
name 部门名称。长度限制为1~64个字符
parentid 父亲部门id。根部门id为1

  • 返回结果
{
   "errcode": 0,
   "errmsg": "created",
   "id": 2
}

根据上面的一些类似的接口定义说明,我们先来定义下组织机构部门数据的维护接口,然后在逐步实现和调用。

        #region 部门管理
        /// <summary>
        ///创建部门。///管理员须拥有“操作通讯录”的接口权限,以及父部门的管理权限。/// </summary>
        CorpDeptCreateJson CreateDept(string accessToken, string name, stringparentId);/// <summary>
        ///更新部门。///管理员须拥有“操作通讯录”的接口权限,以及该部门的管理权限。/// </summary>
        CommonResult DeleteDept(string accessToken, intid);/// <summary>
        ///删除部门.///管理员须拥有“操作通讯录”的接口权限,以及该部门的管理权限。/// </summary>
        CorpDeptListJson ListDept(stringaccessToken);/// <summary>
        ///获取部门列表.///管理员须拥有’获取部门列表’的接口权限,以及对部门的查看权限。/// </summary>
        CommonResult UpdateDept(string accessToken, int id, stringname);#endregion

如创建部门的接口实现如下所示,主要就是构建URL和POST的数据包,然后统一调用并获取返回数据,转换为具体的Json对象实体即可。其他接口的实现方式类似,不在赘述。

        /// <summary>
        ///创建部门。///管理员须拥有“操作通讯录”的接口权限,以及父部门的管理权限。/// </summary>
        public CorpDeptCreateJson CreateDept(string accessToken, string name, stringparentId)
{
string urlFormat = "https://qyapi.weixin.qq.com/cgi-bin/department/create?access_token={0}";var data = new{
name
=name,
parentId
=parentId
};
var url = string.Format(urlFormat, accessToken);var postData =data.ToJson();

CorpDeptCreateJson result
= CorpJsonHelper<CorpDeptCreateJson>.ConvertJson(url, postData);returnresult;
}

CorpDeptCreateJson 对象实体类的定义如下所示,我们主要是根据返回结果进行定义的。

    /// <summary>
    ///创建部门的返回结果/// </summary>
    public classCorpDeptCreateJson : BaseJsonResult
{
/// <summary> ///返回的错误消息/// </summary> public CorpReturnCode errcode { get; set; }/// <summary> ///对返回码的文本描述内容/// </summary> public string errmsg { get; set; }/// <summary> ///创建的部门id。/// </summary> public int id { get; set; }
}

3、部门管理的API调用

上面小节介绍了如何封装部门管理的API,那么我们封装好了对应的接口和接口实现,怎么样在实际环境里面进行调用处理的呢,为了方便我创建一个小的Winform程序来测试对应API的功能,如下所示。

下面我们来介绍一下调用的代码和效果展示。

        private void btnCreateDeleteDept_Click(objectsender, EventArgs e)
{
ICorpAddressBookApi bll
= newCorpAddressBookApi();string name = "测试部门";
CorpDeptCreateJson json
= bll.CreateDept(token, name, "2");if (json != null)
{
Console.WriteLine(
"创建了部门:{0}, ID:{1}", name, json.id);//更新部门信息 name = "测试部门修改名称";
CommonResult result
=bll.UpdateDept(token, json.id, name);if(result != null)
{
Console.WriteLine(
"修改部门名称:{0} {1}", (result.Success ? "成功" : "失败"), result.ErrorMessage);
}
//删除部门 result =bll.DeleteDept(token, json.id);if (result != null)
{
Console.WriteLine(
"删除部门名称:{0} {1}", (result.Success ? "成功" : "失败"), result.ErrorMessage);
}
}

}
        /// <summary>
        ///获取部门列表/// </summary>
        private void btnListDept_Click(objectsender, EventArgs e)
{
ICorpAddressBookApi bll
= newCorpAddressBookApi();
CorpDeptListJson list
=bll.ListDept(token);foreach (CorpDeptJson info inlist.department)
{
string tips = string.Format("{0}:{1}", info.name, info.id);
Console.WriteLine(tips);
}
}

如果对这个《C#开发微信门户及应用》系列感兴趣,可以关注我的其他文章,系列随笔如下所示:

C#开发微信门户及应用(25)-微信企业号的客户端管理功能

C#开发微信门户及应用(24)-微信小店货架信息管理

C#开发微信门户及应用(23)-微信小店商品管理接口的封装和测试

C#开发微信门户及应用(22)-微信小店的开发和使用

C#开发微信门户及应用(21)-微信企业号的消息和事件的接收处理及解密

C#开发微信门户及应用(20)-微信企业号的菜单管理

C#开发微信门户及应用(19)-微信企业号的消息发送(文本、图片、文件、语音、视频、图文消息等)

C#开发微信门户及应用(18)-微信企业号的通讯录管理开发之成员管理

C#开发微信门户及应用(17)-微信企业号的通讯录管理开发之部门管理

C#开发微信门户及应用(16)-微信企业号的配置和使用

C#开发微信门户及应用(15)-微信菜单增加扫一扫、发图片、发地理位置功能

C#开发微信门户及应用(14)-在微信菜单中采用重定向获取用户数据

C#开发微信门户及应用(13)-使用地理位置扩展相关应用

C#开发微信门户及应用(12)-使用语音处理

C#开发微信门户及应用(11)--微信菜单的多种表现方式介绍

C#开发微信门户及应用(10)--在管理系统中同步微信用户分组信息

C#开发微信门户及应用(9)-微信门户菜单管理及提交到微信服务器

C#开发微信门户及应用(8)-微信门户应用管理系统功能介绍

C#开发微信门户及应用(7)-微信多客服功能及开发集成

C#开发微信门户及应用(6)--微信门户菜单的管理操作

C#开发微信门户及应用(5)--用户分组信息管理

C#开发微信门户及应用(4)--关注用户列表及详细信息管理

C#开发微信门户及应用(3)--文本消息和图文消息的应答


C#开发微信门户及应用(2)--微信消息的处理和应答


C#开发微信门户及应用(1)--开始使用微信接口

在上篇随笔《
C#开发微信门户及应用(17)-微信企业号的通讯录管理开发之部门管理

介绍了通讯录的部门的相关操作管理,通讯录管理包括部门管理、成员管理、标签管理三个部分,本篇主要介绍成员的管理操作,包括创建、删除、更新、获取、获取部门成员几个操作要点。

1、成员的创建操作

为了方便,我们可以创建一个部门组织结构,这是开发的前提,因为我们通讯录管理,也是基于一个组织机构下的,如上篇介绍的组织结构层次一样。我这里
创建一个广州爱奇迪的根结构,然后在其中在创建一些组织机构,如下图所示。

在后台可以通过功能操作添加人员,本篇主要介绍如何调用微信企业号API进行人员管理的操作。

创建人员的API定义如下所示。

  • 请求说明

Https请求方式: POST

https://qyapi.weixin.qq.com/cgi-bin/user/create?access_token=ACCESS_TOKEN

请求包结构体为:

{
   "userid": "zhangsan",
   "name": "张三",
   "department": [1, 2],
   "position": "产品经理",
   "mobile": "15913215421",
   "gender": 1,
   "tel": "62394",
   "email": "zhangsan@gzdev.com",
   "weixinid": "zhangsan4dev"
}
  • 参数说明
参数 必须 说明
access_token 调用接口凭证
userid 员工UserID。对应管理端的帐号,企业内必须唯一。长度为1~64个字符
name 成员名称。长度为1~64个字符
department 成员所属部门id列表。注意,每个部门的直属员工上限为1000个
position 职位信息。长度为0~64个字符
mobile 手机号码。企业内必须唯一,mobile/weixinid/email三者不能同时为空
gender 性别。gender=0表示男,=1表示女。默认gender=0
tel 办公电话。长度为0~64个字符
email 邮箱。长度为0~64个字符。企业内必须唯一
weixinid 微信号。企业内必须唯一
  • 权限说明

管理员须拥有“操作通讯录”的接口权限,以及指定部门的管理权限。

  • 返回结果
{
   "errcode": 0,
   "errmsg": "created"
}

我们在C#里面,需要定义对应给的接口,然后根据需要构造对应的传递实体信息。

这里我把人员管理的接口全部定义好,接口定义如下所示。

        #region 部门成员管理
        /// <summary>
        ///创建成员/// </summary>
        CommonResult CreateUser(stringaccessToken, CorpUserJson user);/// <summary>
        ///更新成员/// </summary>
        CommonResult UpdateUser(stringaccessToken, CorpUserUpdateJson user);/// <summary>
        ///删除成员/// </summary>
        CommonResult DeleteUser(string accessToken, stringuserid);/// <summary>
        ///根据成员id获取成员信息/// </summary>
        CorpUserGetJson GetUser(string accessToken, stringuserid);/// <summary>
        ///获取部门成员/// </summary>
        CorpUserListJson GetDeptUser(string accessToken, int department_id, int fetch_child = 0, int status = 0);#endregion

然后根据信息定义,创建一个承载人员信息的CorpUserJson实体对象,创建人员的实现操作代码如下所示。

        /// <summary>
        ///创建成员/// </summary>
        public CommonResult CreateUser(stringaccessToken, CorpUserJson user)
{
string urlFormat = "https://qyapi.weixin.qq.com/cgi-bin/user/create?access_token={0}";var data = new{
userid
=user.userid,
name
=user.name,
department
=user.department,
position
=user.position,
mobile
=user.mobile,
gender
=user.gender,
tel
=user.tel,
email
=user.email,
weixinid
=user.weixinid
};
var url = string.Format(urlFormat, accessToken);var postData =data.ToJson();returnHelper.GetCorpExecuteResult(url, postData);
}

2、成员的更新操作

成员的数据更新和创建操作类似,它的企业号定义如下所示。

  • 请求说明

Https请求方式: POST

https://qyapi.weixin.qq.com/cgi-bin/user/update?access_token=ACCESS_TOKEN

请求包示例如下(如果非必须的字段未指定,则不更新该字段之前的设置值):

{
   "userid": "zhangsan",
   "name": "李四",
   "department": [1],
   "position": "后台工程师",
   "mobile": "15913215421",
   "gender": 1,
   "tel": "62394",
   "email": "zhangsan@gzdev.com",
   "weixinid": "lisifordev",
   "enable": 1
}

由于它的操作数据类似,因此它的实现代码也差不多,如下所示就是。

        /// <summary>
        ///更新成员/// </summary>
        public CommonResult UpdateUser(stringaccessToken, CorpUserUpdateJson user)
{
string urlFormat = "https://qyapi.weixin.qq.com/cgi-bin/user/update?access_token={0}";//string postData = user.ToJson(); var data = new{
userid
=user.userid,
name
=user.name,
department
=user.department,
position
=user.position,
mobile
=user.mobile,
gender
=user.gender,
tel
=user.tel,
email
=user.email,
weixinid
=user.weixinid,
enable
=user.enable
};
var url = string.Format(urlFormat, accessToken);var postData =data.ToJson();returnHelper.GetCorpExecuteResult(url, postData);
}

3、成员的删除、
成员的获取、
部门成员的获取操作

这些操作和上面的类似,不在赘述,主要就是根据需要定义他们对应的返回数据信息,然后解析Json数据即可转换为对应的实体。

1)删除人员的定义如下:

  • 请求说明

Https请求方式: GET

https://qyapi.weixin.qq.com/cgi-bin/user/delete?access_token=ACCESS_TOKEN&userid=lisi

  • 参数说明
参数 必须 说明
access_token 调用接口凭证
userid 员工UserID。对应管理端的帐号
  • 返回结果
{
   "errcode": 0,
   "errmsg": "deleted"
}

2)成员的获取定义如下:

  • 请求说明

Https请求方式: GET

https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&userid=lisi

  • 参数说明
参数 必须 说明
access_token 调用接口凭证
userid 员工UserID
  • 返回结果
{
   "errcode": 0,
   "errmsg": "ok",
   "userid": "zhangsan",
   "name": "李四",
   "department": [1, 2],
   "position": "后台工程师",
   "mobile": "15913215421",
   "gender": 1,
   "tel": "62394",
   "email": "zhangsan@gzdev.com",
   "weixinid": "lisifordev",  
   "avatar": "http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/0",
   "status": 1
}

3)部门成员的获取定义如下:

  • 请求说明

Https请求方式: GET

https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?access_token=ACCESS_TOKEN&department_id=1&fetch_child=0&status=0

  • 参数说明
参数 必须 说明
access_token 调用接口凭证
department_id 获取的部门id
fetch_child 1/0:是否递归获取子部门下面的成员
status 0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加
  • 权限说明

管理员须拥有’获取部门成员’的接口权限,以及指定部门的查看权限。

  • 返回结果
{
   "errcode": 0,
   "errmsg": "ok",
   "userlist": [
           {
                  "userid": "zhangsan",
                  "name": "李四"
           }
     ]
}

这个返回值我们定义一个实体对象用来存储数据即可。

    /// <summary>
    ///获取部门成员返回的数据/// </summary>
    public classCorpUserListJson : BaseJsonResult
{
publicCorpUserListJson()
{
this.userlist = new List<CorpUserSimpleJson>();
}
/// <summary> ///返回的错误消息/// </summary> public CorpReturnCode errcode { get; set; }/// <summary> ///对返回码的文本描述内容/// </summary> public string errmsg { get; set; }/// <summary> ///成员列表/// </summary> public List<CorpUserSimpleJson> userlist { get; set; }
}

7、综合例子调用代码

上面介绍了一些企业号的接口定义和我对API的C#封装接口和部分实现代码,实现了功能后,我们就可以在代码中对它进行测试,确信是否正常使用。

        /// <summary>
        ///人员管理综合性操作(创建、修改、获取信息、删除)/// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnCorpUser_Click(objectsender, EventArgs e)
{
CorpUserJson user
= newCorpUserJson();
user.userid
= "test";
user.name
="测试用户";
user.department
= new List<int>(){2};
user.email
= "test@163.com";

ICorpAddressBookApi bll
= newCorpAddressBookApi();
CommonResult result
=bll.CreateUser(token, user);if (result != null)
{
Console.WriteLine(
"创建成员:{0} {1} {2}", user.name, (result.Success ? "成功" : "失败"), result.ErrorMessage);string name = "修改测试";
user.name
=name;
CorpUserUpdateJson userUpdate
= newCorpUserUpdateJson(user);
result
=bll.UpdateUser(token, userUpdate);if (result != null)
{
Console.WriteLine(
"修改名称:{0} {1} {2}", name, (result.Success ? "成功" : "失败"), result.ErrorMessage);
}

CorpUserGetJson userGet
=bll.GetUser(token, user.userid);if (userGet != null)
{
Console.WriteLine(
"成员名称:{0} ({1} {2})", userGet.name, user.userid, user.email);
}

result
=bll.DeleteUser(token, user.userid);if (result != null)
{
Console.WriteLine(
"删除成员:{0} {1} {2}", name, (result.Success ? "成功" : "失败"), result.ErrorMessage);
}
}
}

获取部门人员的操作代码如下所示。

        /// <summary>
        ///获取部门人员/// </summary>
        private void btnCorpUserList_Click(objectsender, EventArgs e)
{
int deptId = 1;
ICorpAddressBookApi bll
= newCorpAddressBookApi();
CorpUserListJson result
=bll.GetDeptUser(token, deptId);if (result != null)
{
foreach(CorpUserSimpleJson item inresult.userlist)
{
Console.WriteLine(
"成员名称:{0} {1}", item.name, item.userid);
}
}
}

人员的管理,相对来说比较简单,主要是在一定的部门下创建人员,然后也可以给标签增加相应的人员,基本上就是这些了,不过一定需要确保有相应的权限进行操作。

如果对这个《C#开发微信门户及应用》系列感兴趣,可以关注我的其他文章,系列随笔如下所示:

C#开发微信门户及应用(25)-微信企业号的客户端管理功能

C#开发微信门户及应用(24)-微信小店货架信息管理

C#开发微信门户及应用(23)-微信小店商品管理接口的封装和测试

C#开发微信门户及应用(22)-微信小店的开发和使用

C#开发微信门户及应用(21)-微信企业号的消息和事件的接收处理及解密

C#开发微信门户及应用(20)-微信企业号的菜单管理

C#开发微信门户及应用(19)-微信企业号的消息发送(文本、图片、文件、语音、视频、图文消息等)

C#开发微信门户及应用(18)-微信企业号的通讯录管理开发之成员管理

C#开发微信门户及应用(17)-微信企业号的通讯录管理开发之部门管理

C#开发微信门户及应用(16)-微信企业号的配置和使用

C#开发微信门户及应用(15)-微信菜单增加扫一扫、发图片、发地理位置功能

C#开发微信门户及应用(14)-在微信菜单中采用重定向获取用户数据

C#开发微信门户及应用(13)-使用地理位置扩展相关应用

C#开发微信门户及应用(12)-使用语音处理

C#开发微信门户及应用(11)--微信菜单的多种表现方式介绍

C#开发微信门户及应用(10)--在管理系统中同步微信用户分组信息

C#开发微信门户及应用(9)-微信门户菜单管理及提交到微信服务器

C#开发微信门户及应用(8)-微信门户应用管理系统功能介绍

C#开发微信门户及应用(7)-微信多客服功能及开发集成

C#开发微信门户及应用(6)--微信门户菜单的管理操作

C#开发微信门户及应用(5)--用户分组信息管理

C#开发微信门户及应用(4)--关注用户列表及详细信息管理

C#开发微信门户及应用(3)--文本消息和图文消息的应答


C#开发微信门户及应用(2)--微信消息的处理和应答


C#开发微信门户及应用(1)--开始使用微信接口

我们知道,企业号主要是面向企业需求而生的,因此内部消息的交流显得非常重要,而且发送、回复消息数量应该很可观,对于大企业尤其如此,因此可以结合企业号实现内部消息的交流。企业号具有关注安全、消息无限制等特点,很适合企业内部的环境。本文主要介绍如何利用企业号实现文本、图片、文件、语音、视频、图文消息等
消息的发送操作。

1、企业号特点

对于企业号,有以下一些特点:

1)关注更安全

–只有企业通讯录的成员才能关注企业号,分级管理员、保密消息等各种特性确保企业内部信息的安全。

企业可以设置自行验证关注者身份,进行二次安全验证,保证企业信息使用和传递安全。

若员工离职,企业管理员可在通讯录中删除该成员,该成员即自动取消关注企业号,同时微信中的企业号历史记录也会被清除。

2)应用可配置

–企业可自行在企业号中可配置多个服务号,可以连接不同的企业应用系统,只有授权的企业成员才能使用相应的服务号。

3)消息无限制

–发送消息无限制,并提供完善的的管理接口及微信原生能力,以适应企业复杂、个性化的应用场景。

企业可以主动发消息给员工,
消息量不受限制

4)使用更便捷

–企业号在微信中有统一的消息入口,用户可以更方便地管理企业号消息。微信通讯录也可以直接访问企业号中的应用。

2、企业号的管理接口内容

目前企业号的内容可以用下面的分层图来展示,分别包含素材管理、被动响应消息、通讯录管理、自定义菜单等内容,详细可以看下面图示。

3、企业号消息和事件的处理

企业号和公众号一样,可以分为消息处理和事件处理,下面是他们两种类型的处理操作,也就发送的消息有文本消息、图片消息、文件消息、视频消息、语音消息、地理文字消息、图文和多媒体消息等。

事件处理主要就是关注、取消关注事件,以及菜单click类型和view类型两种操作,还有就是地理位置上报事件等。

两种类型的处理图如下所示。

4、企业号消息管理

在企业的管理后台,和公众号一样,可以看到对应信息交流记录,包括文字、图片、地理位置等等,如下所示。

由于消息分为几种类型,包括文本(Text)、图片(Image)、文件(File)、语音(Voice)、视频(Video)、图文消息等(News)、MpNews等。

因此我们需要分别对它们进行一定的定义和封装处理,如下是它们的信息对象设计图。

企业号发送消息的官方定义如下:

企业可以主动发消息给员工,
消息量不受限制

调用接口时,使用Https协议、JSON数据包格式,
数据包不需做加密处理

目前支持文本、图片、语音、视频、文件、图文等消息类型。除了news类型,其它类型的消息可在发送时加上保密选项,保密消息会被打上水印,并且只有接收者才能阅读。

我们以发送的文本消息为例进行说明,它的定义如下所示。

  • text消息
{
   "touser": "UserID1|UserID2|UserID3",
   "toparty": " PartyID1 | PartyID2 ",
   "totag": " TagID1 | TagID2 ",
   "msgtype": "text",
   "agentid": "1",
   "text": {
       "content": "Holiday Request For Pony(http://xxxxx)"
   },
   "safe":"0"
}

参数 必须 说明
touser UserID列表(消息接收者,多个接收者用‘|’分隔)。特殊情况:指定为@all,则向关注该企业应用的全部成员发送
toparty PartyID列表,多个接受者用‘|’分隔。当touser为@all时忽略本参数
totag TagID列表,多个接受者用‘|’分隔。当touser为@all时忽略本参数
msgtype 消息类型,此时固定为:text
agentid 企业应用的id,整型。可在应用的设置页面查看
content 消息内容
safe 表示是否是保密消息,0表示否,1表示是,默认0

其中每种消息都会包含以下消息所示,也就是它们共同的属性:

    touser": "UserID1|UserID2|UserID3","toparty": " PartyID1 | PartyID2 ","totag": " TagID1 | TagID2 ","msgtype": "text","agentid": "1",

因此我们可以定义一个基类用来方便承载这些共同的信息。

    /// <summary>
    ///企业号发送消息的基础消息内容/// </summary>
    public classCorpSendBase
{
/// <summary> ///UserID列表(消息接收者,多个接收者用‘|’分隔)。特殊情况:指定为@all,则向关注该企业应用的全部成员发送/// </summary> public string touser { get; set; }/// <summary> ///PartyID列表,多个接受者用‘|’分隔。当touser为@all时忽略本参数/// </summary> public string toparty { get; set; }/// <summary> ///TagID列表,多个接受者用‘|’分隔。当touser为@all时忽略本参数/// </summary> public string totag { get; set; }/// <summary> ///消息类型/// </summary> public string msgtype { get; set; }/// <summary> ///企业应用的id,整型。可在应用的设置页面查看/// </summary> public string agentid { get; set; }/// <summary> ///表示是否是保密消息,0表示否,1表示是,默认0/// </summary> [JsonProperty(NullValueHandling =NullValueHandling.Ignore)]public string safe { get; set; }

}

然后其他消息逐一继承这个基类即可,如下所示。

最终会构成下面这个继承关系图。

5、消息接口的定义和实现

定义好相关的发送对象后,我们就可以定义它的统一发送接口了,如下所示。

    /// <summary>
    ///企业号消息管理接口定义/// </summary>
    public interfaceICorpMessageApi
{
/// <summary> ///发送消息。///需要管理员对应用有使用权限,对收件人touser、toparty、totag有查看权限,否则本次调用失败。/// </summary> /// <param name="accessToken"></param> /// <returns></returns> CommonResult SendMessage(stringaccessToken, CorpSendBase data);
}

最终,文本等类型的消息会根据接口定义进行实现,实现代码如下所示。
注意,发送过程
不需要
调用加密类进行加密

    /// <summary>
    ///企业号消息管理实现类/// </summary>
    public classCorpMessageApi : ICorpMessageApi
{
/// <summary> ///发送消息。///需要管理员对应用有使用权限,对收件人touser、toparty、totag有查看权限,否则本次调用失败。/// </summary> /// <param name="accessToken"></param> /// <returns></returns> public CommonResult SendMessage(stringaccessToken, CorpSendBase data)
{
CommonResult result
= newCommonResult();string urlFormat = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={0}";var url = string.Format(urlFormat, accessToken);var postData =data.ToJson();//数据不用加密发送 CorpSendResult sendResult = CorpJsonHelper<CorpSendResult>.ConvertJson(url, postData);if (sendResult != null)
{
result.Success
= (sendResult.errcode ==CorpReturnCode.请求成功);
result.ErrorMessage
= string.Format("invaliduser:{0},invalidparty:{1},invalidtag:{2}",
sendResult.invaliduser, sendResult.invalidparty, sendResult.invalidtag);
}
returnresult;
}
}

6、消息的发送操作和实际效果

定义好相应的发送对象后,我们就可以进行统一的消息发送操作,包括文本、图片、文件、语音等等类型的消息,注意有些消息是需要上传到服务器上,然后在根据mediaId进行发送出去的。

发送文本和图片的操作代码如下所示。

        private void btnSendText_Click(objectsender, EventArgs e)
{
//发送文本内容 ICorpMessageApi bll = newCorpMessageApi();

CorpSendText text
= new CorpSendText("API 中文测试(http://www.iqidi.com)");
text.touser
= "wuhuacong";
text.toparty
= "4";//部门ID text.totag = "0";

text.safe
= "0";
text.agentid
= "0";

CommonResult result
=bll.SendMessage(token, text);if (result != null)
{
Console.WriteLine(
"发送消息:{0} {1} {2}", text.text.content, (result.Success ? "成功" : "失败"), result.ErrorMessage);
}
}
private void btnSendImage_Click(objectsender, EventArgs e)
{
btnUpload_Click(sender, e);
if (!string.IsNullOrEmpty(image_mediaId))
{
//发送图片内容 ICorpMessageApi bll = newCorpMessageApi();

CorpSendImage image
= newCorpSendImage(image_mediaId);
CommonResult result
=bll.SendMessage(token, image);if (result != null)
{
Console.WriteLine(
"发送图片消息:{0} {1} {2}", image_mediaId, (result.Success ? "成功" : "失败"), result.ErrorMessage);
}
}
}

最后在微信企业号上截图效果如下所示,包括了文本测试、文件测试、图文测试、语音测试均正常。


如果对这个《C#开发微信门户及应用》系列感兴趣,可以关注我的其他文章,系列随笔如下所示:

C#开发微信门户及应用(25)-微信企业号的客户端管理功能

C#开发微信门户及应用(24)-微信小店货架信息管理

C#开发微信门户及应用(23)-微信小店商品管理接口的封装和测试

C#开发微信门户及应用(22)-微信小店的开发和使用

C#开发微信门户及应用(21)-微信企业号的消息和事件的接收处理及解密

C#开发微信门户及应用(20)-微信企业号的菜单管理

C#开发微信门户及应用(19)-微信企业号的消息发送(文本、图片、文件、语音、视频、图文消息等)

C#开发微信门户及应用(18)-微信企业号的通讯录管理开发之成员管理

C#开发微信门户及应用(17)-微信企业号的通讯录管理开发之部门管理

C#开发微信门户及应用(16)-微信企业号的配置和使用

C#开发微信门户及应用(15)-微信菜单增加扫一扫、发图片、发地理位置功能

C#开发微信门户及应用(14)-在微信菜单中采用重定向获取用户数据

C#开发微信门户及应用(13)-使用地理位置扩展相关应用

C#开发微信门户及应用(12)-使用语音处理

C#开发微信门户及应用(11)--微信菜单的多种表现方式介绍

C#开发微信门户及应用(10)--在管理系统中同步微信用户分组信息

C#开发微信门户及应用(9)-微信门户菜单管理及提交到微信服务器

C#开发微信门户及应用(8)-微信门户应用管理系统功能介绍

C#开发微信门户及应用(7)-微信多客服功能及开发集成

C#开发微信门户及应用(6)--微信门户菜单的管理操作

C#开发微信门户及应用(5)--用户分组信息管理

C#开发微信门户及应用(4)--关注用户列表及详细信息管理

C#开发微信门户及应用(3)--文本消息和图文消息的应答


C#开发微信门户及应用(2)--微信消息的处理和应答


C#开发微信门户及应用(1)--开始使用微信接口

前面几篇陆续介绍了很多微信企业号的相关操作,企业号和公众号一样都可以自定义菜单,因此他们也可以通过API进行菜单的创建、获取列表、删除的操作,因此本篇继续探讨这个主体,介绍企业号的菜单管理操作。

菜单在很多情况下,能够给我们提供一个快速入口,也可以用来获取用户信息的主要入口,通过OAuth2验证接口,以及自定义的重定向菜单,我们就可以获取对应的用户ID,然后进一步获取到用户的相关数据,可以显示给客户。

1、菜单的总体介绍

菜单的事件处理如下所示,包括了单击和跳转两个操作,未来企业号可能会增加一些和公众号一样的扫码操作,拍照操作等功能的,目前只有两个。

官方的菜单定义接口包含了下面三种操作,菜单创建、列表获取和菜单删除,这点和公众号操作几乎一样了。

2、菜单的实体类定义和接口定义处理

我们定义菜单,包括定义它的一些属性,包含有name, type, key,url,以及一个指向自身引用的子菜单引用,因此菜单就可以循环构造多个层次,虽然严格意义上来讲,企业号的菜单和公众号菜单一样,一级三个,二级最多五个,而且没有三级菜单了。

实体类的UML图示如下所示。

菜单管理的创建操作,官方定义如下所示。

  • 请求说明

Https请求方式: POST

https://qyapi.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN&agentid=1

请求包如下:

{
   "button":[
       {	
           "type":"click",
           "name":"今日歌曲",
           "key":"V1001_TODAY_MUSIC"
       },
       {
           "name":"菜单",
           "sub_button":[
               {
                   "type":"view",
                   "name":"搜索",
                   "url":"http://www.soso.com/"
               },
               {
                   "type":"click",
                   "name":"赞一下我们",
                   "key":"V1001_GOOD"
               }
           ]
      }
   ]
}
  • 参数说明
参数 必须 说明
access_token 调用接口凭证
agentid 企业应用的id,整型。可在应用的设置页面查看
button 一级菜单数组,个数应为1~3个
sub_button 二级菜单数组,个数应为1~5个
type 菜单的响应动作类型,目前有click、view两种类型
name 菜单标题,不超过16个字节,子菜单不超过40个字节
key click类型必须 菜单KEY值,用于消息接口推送,不超过128字节
url view类型必须 网页链接,员工点击菜单可打开链接,不超过256字节
  • 权限说明

管理员须拥有应用的管理权限,并且应用必须设置在回调模式。

返回结果

{
   "errcode":0,
   "errmsg":"ok"
}

根据上面官方的定义语义,我们菜单管理的C#管理接口定义如下所示。

    /// <summary>
    ///企业号菜单管理接口定义/// </summary>
    public interfaceICorpMenuApi
{
/// <summary> ///获取菜单数据/// </summary> /// <param name="accessToken">调用接口凭证</param> /// <returns></returns> MenuListJson GetMenu(string accessToken, stringagentid);/// <summary> ///创建菜单/// </summary> /// <param name="accessToken">调用接口凭证</param> /// <param name="menuJson">菜单对象</param> /// <returns></returns> CommonResult CreateMenu(string accessToken, MenuListJson menuJson, stringagentid);/// <summary> ///删除菜单/// </summary> /// <param name="accessToken">调用接口凭证</param> /// <returns></returns> CommonResult DeleteMenu(string accessToken, stringagentid);
}

我们以创建菜单的实现为例来介绍微信企业号菜单的操作,其他的操作类似处理,都是返回一个公共的消息类,方便处理和读取,代码如下所示。

        /// <summary>
        ///创建菜单/// </summary>
        /// <param name="accessToken">调用接口凭证</param>
        /// <param name="menuJson">菜单对象</param>
        /// <returns></returns>
        public CommonResult CreateMenu(string accessToken, MenuListJson menuJson, stringagentid)
{
var url = string.Format("https://qyapi.weixin.qq.com/cgi-bin/menu/create?access_token={0}&agentid={1}", accessToken, agentid);string postData =menuJson.ToJson();returnHelper.GetCorpExecuteResult(url, postData);
}

3、企业号菜单管理接口的调用和处理效果

调用的代码和效果图如下所示。

        private void btnMenuCreate_Click(objectsender, EventArgs e)
{
MenuJson productInfo
= new MenuJson("产品介绍", newMenuJson[] {new MenuJson("软件产品介绍", ButtonType.click, "event-software")
,
new MenuJson("框架源码产品", ButtonType.click, "event-source")
,
new MenuJson("软件定制开发", ButtonType.click, "event-develop")
});

MenuJson frameworkInfo
= new MenuJson("框架产品", newMenuJson[] {new MenuJson("Win开发框架", ButtonType.click, "win"),new MenuJson("WCF开发框架", ButtonType.click, "wcf"),new MenuJson("混合式框架", ButtonType.click, "mix"),new MenuJson("Web开发框架", ButtonType.click, "web")
,
new MenuJson("代码生成工具", ButtonType.click, "database2sharp")
});

MenuJson relatedInfo
= new MenuJson("相关链接", newMenuJson[] {new MenuJson("公司介绍", ButtonType.click, "event_company"),new MenuJson("官方网站", ButtonType.view, "http://www.iqidi.com"),new MenuJson("联系我们", ButtonType.click, "event_contact"),new MenuJson("应答系统", ButtonType.click, "set-1"),new MenuJson("发邮件", ButtonType.view, "http://mail.qq.com/cgi-bin/qm_share?t=qm_mailme&email=S31yfX15fn8LOjplKCQm")
});

MenuListJson menuJson
= newMenuListJson();
menuJson.button.AddRange(
newMenuJson[] { productInfo, frameworkInfo, relatedInfo });//Console.WriteLine(menuJson.ToJson()); if (MessageUtil.ShowYesNoAndWarning("您确认要创建菜单吗") ==System.Windows.Forms.DialogResult.Yes)
{
ICorpMenuApi bll
= newCorpMenuApi();
CommonResult result
=bll.CreateMenu(token, menuJson, agentid);
Console.WriteLine(
"创建菜单:" + (result.Success ? "成功" : "失败:" +result.ErrorMessage));
}
}
private void btnMenuGet_Click(objectsender, EventArgs e)
{
ICorpMenuApi bll
= newCorpMenuApi();
MenuListJson menu
=bll.GetMenu(token, agentid);if (menu != null)
{
Console.WriteLine(menu.ToJson());
}
}

调用代码的测试输出如下所示。

如果对这个《C#开发微信门户及应用》系列感兴趣,可以关注我的其他文章,系列随笔如下所示:

C#开发微信门户及应用(25)-微信企业号的客户端管理功能

C#开发微信门户及应用(24)-微信小店货架信息管理

C#开发微信门户及应用(23)-微信小店商品管理接口的封装和测试

C#开发微信门户及应用(22)-微信小店的开发和使用

C#开发微信门户及应用(21)-微信企业号的消息和事件的接收处理及解密

C#开发微信门户及应用(20)-微信企业号的菜单管理

C#开发微信门户及应用(19)-微信企业号的消息发送(文本、图片、文件、语音、视频、图文消息等)

C#开发微信门户及应用(18)-微信企业号的通讯录管理开发之成员管理

C#开发微信门户及应用(17)-微信企业号的通讯录管理开发之部门管理

C#开发微信门户及应用(16)-微信企业号的配置和使用

C#开发微信门户及应用(15)-微信菜单增加扫一扫、发图片、发地理位置功能

C#开发微信门户及应用(14)-在微信菜单中采用重定向获取用户数据

C#开发微信门户及应用(13)-使用地理位置扩展相关应用

C#开发微信门户及应用(12)-使用语音处理

C#开发微信门户及应用(11)--微信菜单的多种表现方式介绍

C#开发微信门户及应用(10)--在管理系统中同步微信用户分组信息

C#开发微信门户及应用(9)-微信门户菜单管理及提交到微信服务器

C#开发微信门户及应用(8)-微信门户应用管理系统功能介绍

C#开发微信门户及应用(7)-微信多客服功能及开发集成

C#开发微信门户及应用(6)--微信门户菜单的管理操作

C#开发微信门户及应用(5)--用户分组信息管理

C#开发微信门户及应用(4)--关注用户列表及详细信息管理

C#开发微信门户及应用(3)--文本消息和图文消息的应答


C#开发微信门户及应用(2)--微信消息的处理和应答


C#开发微信门户及应用(1)--开始使用微信接口