Magicodes.Wx.Sdk致力於打造最簡潔最易於使用的微信Sdk,逐步包括公衆號Sdk、小程序Sdk、企業微信Sdk等,以及Abp VNext集成。html
本篇將側重於講述如何向Magicodes.Wx.Sdk進行貢獻。git
Magicodes.Wx.Sdk之簡潔很大層面依託於NCC的開源庫WebApiClientCore。Magicodes.Wx.Sdk依託WebApiClientCore完成了微信接口的包裝和校驗。github
開源庫地址:https://github.com/dotnetcore/WebApiClientweb
這裏咱們以【客服消息】【添加客服帳號】爲例進行講解,官方接口文檔地址爲:https://developers.weixin.qq.com/doc/offiaccount/Customer_Service/Customer_Service_Management.html#2。小程序
好比添加客服帳號接口官方接口文檔說明以下所示:api
主體步驟以下:微信
參考代碼以下所示:框架
/// <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); }
如上述代碼所示,有幾個注意事項:async
須要定義接口ide
繼承自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表單字段與值 | 常量鍵和值 |
這一步是非必要的,須要看參數的具體內容和要求。添加客服接口的輸入參數代碼參考以下:
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粘貼爲類】:
框架中封裝了默認的返回結果基類,若是沒有其餘額外的返回內容,僅需返回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就能夠了。是否是很是簡單?
/// <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
接口用於定義須要攜帶公衆號Acces sToken的接口。
以下述參考代碼所示,其啓用了AccessTokenApiFilter
篩選器,以及關閉了AcceptContentType的匹配約束(公衆號的接口官方寫的一塌糊塗,很不規範)。
參考代碼:
/// <summary> /// /// </summary> [JsonNetReturn(EnsureMatchAcceptContentType = false)] [AccessTokenApiFilter] //[LoggingFilter] public interface IWxApiWithAccessTokenFilter { }
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; } }
ApiResultBase定義了公衆號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(); } }