Magicodes.Wx.Sdk之30秒编写一个微信接口
移动开发和人工智能 4天前以下文章来源于麦扣聊技术 ,作者magiccodes出容器、产品开发管理、微服务架构系列文章和教程:docs.xin-lai.com。概述Magicodes.Wx.Sdk致力于打造最简洁最易于使用的微信Sdk,逐步包括公众号Sdk、小程序Sdk、企业微信Sdk等,以及Abp VNext集成。本篇将侧重于讲述如何向Magicodes.Wx.Sdk进行贡献。WebApiClientCoreMagicodes.Wx.Sdk之简洁很大层面依托于NCC的开源库WebApiClientCore。Magicodes.Wx.Sdk依托WebApiClientCore完成了微信接口的包装和校验。开源库地址:https://github.com/dotnetcore/WebApiClient快速开始这里我们以【客服消息】【添加客服账号】为例进行讲解,官方接口文档地址为:https://developers.weixin.qq.com/doc/offiaccount/Customer_Service/Customer_Service_Management.html#2。比如添加客服账号接口官方接口文档说明如下所示:
主体步骤如下:1)添加接口IKfAccountApi参考代码如下所示:/// <summary>/// 客服管理/// </summary>[HttpHost("https://api.weixin.qq.com/customservice/kfaccount/")]public interface IKfAccountApi : IWxApiWithAccessTokenFilter{ /// <summary> /// 添加客服账号 /// </summary> /// <param name="input"></param> /// <returns></returns> [HttpPost("add")] Task<ApiResultBase> AddAsync(AddOrUpdateKfAccountInput input);/// <summary> /// 设置客服信息 /// </summary> /// <param name="input"></param> /// <returns></returns> [HttpPost("update")] Task<ApiResultBase> UpdateAsync(AddOrUpdateKfAccountInput input);/// <summary> /// 删除客服账号 /// </summary> /// <param name="input"></param> /// <returns></returns> [HttpPost("del")] Task<ApiResultBase> DelAsync(DelKfAccountInput input);}如上述代码所示,有几个注意事项:需要定义接口继承自IWxApiWithAccessTokenFilter接口将自动在接口请求启用AccessTokenApiFilter筛选器,即会自动会在接口请求时带上access_token。HttpHost用于定义接口跟地址HttpPost用于设置接口请求方法,常用特性有:特性名称功能描述备注HttpHostAttribute请求服务http绝对完整主机域名优先级比Options配置低HttpGetAttribute声明Get请求方法与路径支持null、绝对或相对路径HttpPostAttribute声明Post请求方法与路径支持null、绝对或相对路径HttpPutAttribute声明Put请求方法与路径支持null、绝对或相对路径HttpDeleteAttribute声明Delete请求方法与路径支持null、绝对或相对路径HeaderAttribute声明请求头常量值TimeoutAttribute声明超时时间常量值FormFieldAttribute声明Form表单字段与值常量键和值FormDataTextAttribute声明FormData表单字段与值常量键和值2)添加Dto这一步是非必要的,需要看参数的具体内容和要求。添加客服接口的输入参数代码参考如下:public class AddOrUpdateKfAccountInput { /// <summary> /// 完整客服账号,格式为:账号前缀@公众号微信号,账号前缀最多10个字符,必须是英文、数字字符或者下划线,后缀为公众号微信号,长度不超过30个字符 /// </summary> [JsonProperty("kf_account")] [StringLength(30, MinimumLength = 3)] [Required] public string Account { get; set; }/// <summary> /// 客服昵称,最长16个字 /// </summary> [JsonProperty("nickname")] [StringLength(16, MinimumLength = 1)] public string Nickname { get; set; } }Dto实体的添加这里给大家分享一个小技巧。当实体字段以及层级比较多时,大家可以使用VS的【编辑】==》【选择性粘贴】==》【将Json粘贴为类】:
3)添加ApiResultBase框架中封装了默认的返回结果基类,如果没有其他额外的返回内容,仅需返回ApiResultBase即可。如果有额外的范围内容,则需要定义子类继承自ApiResultBase,在可能的情况下,有可能需要重写部分方法(比如IsSuccess)。如下述代码:public class TokenApiResult : ApiResultBase{ /// <summary> /// 获取到的凭证 /// </summary> [JsonProperty("access_token")] public string AccessToken { get; set; }/// <summary> /// 凭证有效时间,单位:秒 /// </summary> [JsonProperty("expires_in")] internal int Expires { get; set; }/// <summary> /// 凭证过期时间 /// </summary> public DateTime ExpiresTime { get; set; }}至此,一个接口就编写完成了。只需要定义interface和Dto就可以了。是不是非常简单?4)单元测试编写/// <summary>/// 模板消息单元测试/// </summary>public class TemplateApiTest : TestBase, IClassFixture<TestWebApplicationFactory>{ private readonly ITemplateApi templateApi; public TemplateApiTest(TestWebApplicationFactory webApplicationFactory, ITestOutputHelper output) : base(webApplicationFactory, output) { //通过父类的GetRequiredService获取到Api templateApi = GetRequiredService<ITemplateApi>(); }/// <summary> /// 模板消息发送测试 /// </summary> /// <returns></returns> [Fact] public async Task SendAsync_Test() { var result = await templateApi.SendAsync(new SendTemplateMessageInput() { To = "oXELNwzZgamuLS0JrJhVgdelzKyw", TemplateId = "riid7aad8OKRQD9Ey6dclWBBkrqZSFDhlpKh0_spGLA", Data = new System.Collections.Generic.Dictionary<string, TemplateDataItem>() { {"first",new TemplateDataItem("测试") }, {"keyword1",new TemplateDataItem("雪雁") }, {"keyword2",new TemplateDataItem("2021.2.5") }, {"remark",new TemplateDataItem("备注") }, } }); //判断Api是否调用成功,未成功将抛出异常WxSdkException result.EnsureSuccess(); }}整体参考:https://github.com/xin-lai/Magicodes.Wx.Sdk/pull/1/commits/85263ed9a807581f7315a90fe6e00c51c994d386其他须知内容IWxApiWithAccessTokenFilter接口IWxApiWithAccessTokenFilter接口用于定义需要携带公众号Acces sToken的接口。如下述参考代码所示,其启用了AccessTokenApiFilter筛选器,以及关闭了AcceptContentType的匹配约束(公众号的接口官方写的一塌糊涂,很不规范)。参考代码:/// <summary>/// /// </summary>[JsonNetReturn(EnsureMatchAcceptContentType = false)][AccessTokenApiFilter]//[LoggingFilter]public interface IWxApiWithAccessTokenFilter{}AccessTokenApiFilter筛选器AccessTokenApiFilter接口筛选器会在启用的API、Action上自动添加access_token参数值。参考代码如下所示:public class AccessTokenApiFilter : ApiFilterAttribute{ public override async Task OnRequestAsync(ApiRequestContext context) { ITokenManager tokenManager = context.HttpContext.ServiceProvider.GetRequiredService<ITokenManager>(); string accessToken = await tokenManager.GetAccessTokenAsync(); context.HttpContext.RequestMessage.AddUrlQuery("access_token", accessToken); }public override Task OnResponseAsync(ApiResponseContext context) { return Task.CompletedTask; }}关于ApiResultBaseApiResultBase定义了公众号API返回基类,用于接收错误码、错误消息、是否执行成功的判断以及获取友好消息提示。参考代码:/// <summary>/// API请求结果/// {"errcode":40164,"errmsg":"invalid ip 218.76.8.29 ipv6 ::ffff:218.76.8.29, not in whitelist rid: 60122c35-705c3134-51b45a3d"}/// </summary>public class ApiResultBase{ /// <summary> /// 返回码 /// </summary> [JsonProperty("errcode")] public virtual ReturnCodes ReturnCode { get; set; }/// <summary> /// 错误消息 /// </summary> [JsonProperty("errmsg")] public virtual string Message { get; set; }/// <summary> /// 是否为成功返回 /// </summary> /// <returns></returns> public virtual bool IsSuccess() { return ReturnCode == ReturnCodes.请求成功; }/// <summary> /// 获取友好提示 /// </summary> /// <returns></returns> public virtual string GetFriendlyMessage() { return ReturnCode.ToString(); }}《轻量易用的微信Sdk发布——Magicodes.Wx.Sdk》