1、前言
時間飛快,轉眼半年,碌碌無為,眼下就要三十而立,回想三年前的今天,我將NetworkSocket庫開放到github,一直在更新與學習,不求有這個庫能有多好,只求自己在過程能成長,將領悟到一些思想應用到庫里面去。今天,我來給大家介紹半年前在github開放的WebApiClient這個庫,正如NetworkSocket一樣,它正在漸漸從渺小變得強大,從簡單變得抽象、易用、可高度擴展,它將帶你進入不一個和以往完全不同風格的調用http接口的世界。
2、編程風格
2.1傳統調用風格
一般的,我們需要new 一個HttpClient實例,然后准備請求url、請求body的HttpContent,然后發送,等待接收,解析回復內容.....
這些都是需要一行一行代碼來實現,代碼里不僅表現了“做什么(What)”,而且更多表現出“如何(How)”完成工作這樣的實現細節,大概想想代碼像下面:

/// <summary> /// 更新用戶信息 /// 使用application/json提交 /// </summary> /// <param name="user"></param> /// <returns></returns> async static Task<UserInfo> UpdateAsync(UserInfo user) { var httpClient = new HttpClient(); var serializer = new JavaScriptSerializer(); var json = serializer.Serialize(user); var content = new StringContent(json, Encoding.UTF8, "application/json"); var url = "http://localhost:9999/webapi/user/updateWithJson"; var response = await httpClient.PostAsync(url, content); var resJson = await response.Content.ReadAsStringAsync(); var resUser = serializer.Deserialize<UserInfo>(resJson); return resUser; }
服務端任何接口的小變化,都直接影響到我們接口調用的某行具體代碼,如果有100個接口,這代碼的維護也不小。
2.2WebApiClient風格
WebApiClient的設計可以解放使用者的勞動力,只需要使用者根據http接口來定義一份.Net的interface,在接口里描述你想要什么(what i wan),但不需要實現這份interface(how it do),大概如下:
[HttpHost("http://localhost:9999")] public interface UserApi { [HttpPost("/webapi/user/UpdateWithJson")] Task<UserInfo> UpdateWithJsonAsync([JsonContent] UserInfo user); }
那么,接口的實現者給誰來完成呢?給WebApiClient來完成,它很聰明,知道你想要什么,這個正像我們寫一條sql:select * from table一樣,只有what,沒有how。
3、使用層設計
3.1接口與服務端設計一致
使用者編寫的interface,可以與服務端接近完全一致,在編寫接口或文檔對照方面相當容易。
3.2使用Attribute標記描述“干什么”
上面的[HttpPost]和[JsonContent],用來標記是干什么(不是怎么干)
3.3沒有了,只剩下調用接口了
var userApi = new HttpApiClient().Implement<UserApi>(); var resUser = await userApi.UpdateWithJsonAsync(user);
4、架構層設計
使用Castle來動態實現interface的實例,並獲得實例方法調用的攔截,在攔截層,一一調用與方法相關標記的Atribute,Attribute是真正的邏輯實現者,每個Attribute只關注自己應該做什么。
4.1、ApiActionContext
ApiActionContext用於描述接口的詳細信息以及接口周邊的其它信息,在攔截interface的實例某方法之后,都生成一份ApiActionContext實例,但實例的很多屬性是緩存中獲取的,任何特性在執行的時候,都可以訪問和修改這個ApiActionContext。
4.2、Attribute標記分類
1、IHttpActionAttribute (ApiActionContext) // 與Api方法相關
2、IApiParameterAttribute (ApiActionContext) // 與 api參數相關
3、IApiActionFilterAttribute (ApiActionContext) // 與Api請求前后有關
4、IApiReturnAttribute (ApiActionContext) // 與api返回值相關
這4個Attribute接口有着各自的職責,前三者一個共同的目標:構造和影響一個請求內容對象HttpRequestMessage,第4個的目標是:從回復的HttpResponseMessage中得到接口的返回值
4.3 Attribute的執行
在攔截器里,按照IApiActionAttribute > IApiParameterAttribute > IApiActionFilterAttribute > IApiReturnAttribute的順序,將與方法的所有特性都執行,就可以完成接口的調用,大概實現如下:
/// <summary> /// 異步執行api /// </summary> /// <param name="context">上下文</param> /// <returns></returns> private async Task<object> ExecuteInternalAsync(ApiActionContext context) { var apiAction = context.ApiActionDescriptor; foreach (var actionAttribute in apiAction.Attributes) { await actionAttribute.BeforeRequestAsync(context); } foreach (var parameter in apiAction.Parameters) { foreach (var parameterAttribute in parameter.Attributes) { await parameterAttribute.BeforeRequestAsync(context, parameter); } } foreach (var filter in apiAction.Filters) { await filter.OnBeginRequestAsync(context); } // 執行Http請求,獲取回復對象 var httpClient = context.HttpClientContext.HttpClient; context.ResponseMessage = await httpClient.SendAsync(context.RequestMessage); foreach (var filter in apiAction.Filters) { await filter.OnEndRequestAsync(context); } return await apiAction.Return.Attribute.GetTaskResult(context); }
5、支持的功能特性
5.1方法或接口級特性
絕對主機域名:[HttpHost]
請求方式與路徑:[HttpGet]、[HttpPost]、[HttpDelete]、[HttpPut]、[HttpHead]和[HttpOptions]
代理:[Proxy]
請求頭:[Header]
返回值:[AutoReturn]、[JsonReturn]、[XmlReturn]
使用者可以自己擴充更多特性。
5.2 參數級特性
路徑或query:[PathQuery]、[Url]
請求頭:[Header]
請求Body:[HttpContent]、[JsonContent]、[XmlContent]、[FormContent]、[MulitpartConten]
使用者可以自己擴充更多特性。
5.3特殊參數類型
MulitpartFile類(表單文件)、Url類(請求地址)、Proxy類 (請求代理)
這些特殊參數類型在參數里,可以是本類型或本類型的集合,都會被執行
使用者可以自己擴充更多的特殊參數類型。
6、擴展能力
6.1 擴展特性
任何只要實現了IHttpActionAttribute、IApiParameterAttribute 、IApiActionFilterAttribute 、IApiReturnAttribute 之一或以上的特性,只要打在接口或參數上,就會得到調用,在調用里實現處理邏輯。
6.2 特殊參數擴展
任何實現了IApiParameterable接口的參數值,也會得到調用。
6.3 自定義xml/json序列化
HttpApiClient.Config.UseXmlFormatter(your formatter)
HttpApiClient.Config.UseJsonFormatter(your formatter)
6.4 自定義HttpClient上下文提供者
HttpApiClient.Config.UseHttpClientContextProvider(your provider)
你可以自己控制HttpClient的配置與生命周期
6.5 自定義過濾器
繼承ApiActionFilterAttribute,可以實現自己的攔截器,作日志、授權什么的都可以;
在子類修改AllowMultiple屬性與OrderIndex屬性,可以實現特性的排序與是否在接口和方法上重復使用。
7、項目地址
https://github.com/xljiulang/WebApiClient
里面有一個demo,借助networksocket,http服務端與客戶端都是同一個進程,調試過程非常方便,數據流向一目了然。
最后,如果你看哪個哪.net 的httpClient有更方便的調用,請@我,我馬上模仿他。