概述
Magicodes.Wx.Sdk致力於打造最簡潔最易於使用的微信Sdk,逐步包括公眾號Sdk、小程式Sdk、企業微信Sdk等,以及Abp VNext整合。
本篇將側重於講述如何向Magicodes.Wx.Sdk進行貢獻。
WebApiClientCore
Magicodes.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; } }
關於ApiResultBase
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(); } }