.NET6用起来-飞书dotnet sdk

最近有用到飞书开放平台的功能,然后在github上找了下,没找到对应的sdk,于是自己封装了一个飞书dotnet sdk,方便调用,只需要结合官网文档,传递对应的参数,接收到返回的数据。
一、飞书开放平台服务端api约定和实现
api请求约定:
基本信息:{api的url、http method(GET or POST)}
请求头:{访问凭证(token)、http content-type}
路径参数:{放置在url中,以:开头}
查询参数:{这部分参数需要在 URL 后使用?进行连接,多个查询参数间以&分隔}
请求体:这部分参数需要放在 HTTP 请求的 Body 中,一般为 JSON 格式
api请求实现:
1.创建一个类库项目(dotnet-feishu)

2.定义个飞书请求的接口(IFeishuRequest),所有的请求都会继承它
public interface IFeishuRequestwhere T : BaseResponse {public string GetUrl();public string GetHttpMethod();////// 获取所有的Key-Value形式的文本请求参数字典。///IDictionary<string, object> GetParameters();////// 获取自定义HTTP请求头参数。///IDictionary<string, string> GetHeaderParameters();////// 获取路径参数 已:路径参数名称 在url中//////IDictionary<string, string> GetPathParameters();}
再定义一个抽象的请求基类(BaseRequest),实现接口IFeishuRequest部分的方法,如:header、path参数的get和add和httpMethod的set和get。
public abstract class BaseRequest: IFeishuRequestwhere T : BaseResponse {private String httpMethod = "POST";private IDictionary<string, string> headerParams;private IDictionary<string, string> pathParams;public string GetHttpMethod(){return httpMethod;}public abstract string GetUrl();public IDictionary<string, string> GetHeaderParameters(){if (this.headerParams == null){this.headerParams = new Dictionary<string, string>();}return this.headerParams;}public void AddHeaderParameter(string key, string value){GetHeaderParameters().Add(key, value);}////// 设置请求////// 默认POSTpublic void SetHttpMethod(String httpMethod){this.httpMethod = httpMethod;}public IDictionary<string, string> GetPathParameters(){if (this.pathParams == null){this.pathParams = new Dictionary<string, string>();}return this.pathParams;}public void AddPathParameter(string key, string value){GetPathParameters().Add($":{key}", value);}public abstract IDictionary<string, object> GetParameters();}
具体的请求需要实现BaseRequest,来实现获取api的url 和 api的请求参数。以获取访问凭证接口为例:
public class GetTenantAccessTokenRequest : BaseRequest<GetTenantAccessTokenResponse>{[JsonProperty("app_id")]public string AppId { get; set; }[JsonProperty("app_secret")]public string AppSecret { get; set; }public override IDictionaryobject > GetParameters(){IDictionaryobject > keyValues = new Dictionaryobject>(); keyValues.Add("app_id", this.AppId);keyValues.Add("app_secret", this.AppSecret);return keyValues;}public override string GetUrl(){return $"{FeiShuConstant.BASE_URL}/open-apis/auth/v3/tenant_access_token/internal";}}
api响应(返回值)约定:
绝大多数 API 的响应体结构包括 code、msg、data 三个部分。
code为错误码,msg为错误信息,data为 API 的调用结果。默认请求成功时,code 为 0,msg 为 success。data 在一些操作类 API 的返回中可能不存在。
api响应实现:
定义一个返回的基类BaseResponse,定义两个属性,如:
public class BaseResponse{////// 返回码///[]public int Code { get; set; }////// 返回消息///[]public string Msg { get; set; }}
具体api的返回需要继承BaseResponse,还是以获取访问token为例,如:
public class GetTenantAccessTokenResponse : BaseResponse{[]public string TenantAccessToken { get; set; }[]public int Expire { get; set; }}
api的请求和响应部分实现已经完成了,如何执行调用飞书api呢?主要利用IHttpClientFactory创建httpclient进行调用,代码如下:
public async TaskExcueAsync (IFeishuRequest req) where T : BaseResponse {var httpClient = _httpClientFactory.CreateClient();var response = new HttpResponseMessage();var paras = req.GetParameters();var dicHeader = req.GetHeaderParameters();var dicPath = req.GetPathParameters();httpClient.DefaultRequestHeaders.Clear();foreach (var kv in dicHeader){var value = kv.Key == "Authorization"? "Bearer " + kv.Value : kv.Value;httpClient.DefaultRequestHeaders.Add(kv.Key, value);}var httpUrl = req.GetUrl();if (dicPath.Count()>0){httpUrl = httpUrl.Replace($"{dicPath.First().Key}", dicPath.First().Value);}if (req.GetHttpMethod() == "POST"){//body jsonvar jsonParas = JsonConvert.SerializeObject(paras);StringContent stringContent = new StringContent(jsonParas, Encoding.UTF8, "application/json");response = await httpClient.PostAsync(req.GetUrl(), stringContent);}else{//querystring KEY=VALUE & KEY=VALUEvar serverUrl = string.Empty;var queryString = HttpClientUtil.GetQueryString(paras);if (httpUrl.IndexOf("?") > 0){serverUrl = httpUrl + "&" + queryString;}else{serverUrl = httpUrl + "?" + queryString;}response = await httpClient.GetAsync(serverUrl);}var content = await response.Content.ReadAsStringAsync();return JsonConvert.DeserializeObject(content); }
以上是请求、响应代码的封装,以及请求飞书api的代码,下面演示如何使用。
二、dotnet飞书sdk的使用
大致调用流程:new api请求实例并进行赋值,调用IFeishuClient的ExcueAsync方法,返回api结构体。
创建一个单元测试项目(Test-Feishu)如图:

添加TestGetTenantAccessToken方法,测试获取访问凭证api
////// 获取token///[]public async Task<string> TestGetTenantAccessToken(){if (!_memoryCache.TryGetValue("token", out string cacheValue)){//测试获取tokenvar req = new GetTenantAccessTokenRequest();req.AppId = AppSetting.FeiShuAppId;req.AppSecret = AppSetting.FeiShuAppSecret;var getTenantAccessTokenResponse = await _feishuClient.ExcueAsync(req);cacheValue = getTenantAccessTokenResponse.TenantAccessToken;var cacheEntryOptions = new MemoryCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromSeconds(getTenantAccessTokenResponse.Expire));_memoryCache.Set("token", cacheValue, cacheEntryOptions);Assert.True(getTenantAccessTokenResponse.Code == 0);}return cacheValue;}
如代码所示,我们访问一个飞书api接口,只需要 new GetTenantAccessTokenRequest(),然后调用IFeishuClient的ExcueAsync方法,返回值就是对应飞书返回的结构体。

到此,封装的代码已经结束,后面代码会上传到github上。
参考:
飞书开放平台:https://open.feishu.cn/document/ukTMukTMukTM/uITNz4iM1MjLyUzM
