.net的retrofit--WebApiClient底层篇
前言
本篇文章的內容是WebApiClient底層說明,也是WebApiClient系列接近尾聲的一篇文章,如果你沒有閱讀過之前的的相關文章,可能會覺得本文章的內容斷層
庫簡介
WebApiClient是開源在github上的一個httpClient客戶端庫,內部基于HttpClient開發,是一個只需要定義c#接口(interface),并打上相關特性,即可異步調用http-api的框架 ,支持.net framework4.5+、netcoreapp2.0和netstandard2.0。
WebApiClient是我2017年看到java的retrofit庫之后,決心給.net打造的一款面向切面的httpclient客戶端庫,在開發過程中陸續發現.net下也有一些HttpClient包裝庫,WebApiClient庫雖然是后起,卻有其它庫所沒有很多優秀特征:
原生的支持面向切面編程;
內置豐富的特性,支持自定義特性;
靈活和Filter、GlobalFilter和IParameterable;
功能強大的序列化工具;
與外部HttpClientHandler無縫銜接;
獨一無二的請求異常條件重試功能和異常處理鏈式語法功能
1. HttpRequestMessage簡說
System.Net.Http.HttpRequestMessage表示一個請求消息,一般而言它包含一個完整的請求數據,主要由請求頭和請求體組成,對于Post、Delete、Put等請求,其Content屬性包含提交的數據體內容。
WebApiClient的ApiActionContex對象有個RequestMessage對象,是派生于HttpRequestMessage,同時實現了多個Addxxx方法用于給其屬性Content對象添加數據內容。
2. HttpClientHandler簡說
System.Net.Http.HttpClientHandler是一個與tcp層相關的對象,負責與遠程服務器進行tcp連接,將HttpRequestMessage轉換為http請求包發送給服務端,并等待服務端的響應。(以上這段話是我瞎說,僅供討論)一般的網絡相關配置的證書、代理和認證等在都在這里可以配置。
3. HttpClient簡說
System.Net.Http.HttpClient必須與HttpClientHandler關聯才能使用,一個HttpRequestMessage經過HttpClient之后,HttpClient的一些默認配置會影響到它,比如默認請求頭等。HttpClient是使用關聯的HttpClientHandler將HttpRequestMessage發送出去,也就是說,完全可以跳過HttpClient而使用HttpClientHandler來發送請求,方法是寫一個類,繼承于HttpClientHandler并公開一個方法,調用基類的SendAsync方法就可以發送請求。
4. WebApiClient庫的HttpClient配置
WebApiClient庫是對HttpClient的封裝,所有的配置項在HttpApiConfig對象, 實例化HttpApiConfig對象時有個構造器可以傳入IHttpClient的實例,而IHttpClient是對System.Net.Http.HttpClient的一個包裝接口定義,WebApiClient.Defaults.HttpClient是對IHttpClient接口的一個實現,才下代碼是WebApiCient與System.Net.Http.HttpClient的一個銜接:
IHttpClient client = new WebApiClient.Defaults.HttpClient();var config = new WebApiClient.HttpApiConfig(client);5. IHttpClient接口
5.1 IHttpClient的接口定義
/// <summary> 定義HttpClient的接口/// </summary>
public interface IHttpClient : IDisposable{ ? ?
? ? /// <summary>/// 獲取關聯的Http處理對象/// </summary>HttpClientHandler Handler { get; } ? ?
? ?/// <summary>/// 獲取默認的請求頭管理對象/// </summary>HttpRequestHeaders DefaultRequestHeaders { get; } ? ?
? ?/// <summary>/// 異步發送請求/// </summary>/// <param name="request">請求消息</param>/// <returns></returns>Task<HttpResponseMessage> SendAsync(HttpApiRequestMessage request);... }
5.2 IHttpClient的接口意圖
IHttpClient接口意圖將System.Net.Http.HttpClient實例和System.Net.Http.HttpClientHandler實例進行組合封裝,隱藏底層的一些細節,同時描述了HttpClient和HttpClientHandler不可分割的關系,其默認實現對象WebApiClient.Defaults.HttpClient將System.Net.Http.HttpClient難用的幾個功能也封裝了一次:比如設置Cookie和設置代理等。
5.3 更換WebApiClient.Defaults.HttpClient關聯的HttpClientHandler
一般而言,HttpClient沒有多少擴展的價值,但HttpClientHandler就有很多擴展空間,其中System.Net.Http.WebRequestHandler也派生于HttpClientHandler,多了很一些配置的屬性,很多時候,需要替換WebApiClient.Defaults.HttpClient的HttpClientHandler就可以,而不用從頭實現IHttpClient接口,以下方式可以替換HttpClientHandler:
class MyHttpClient : WebApiClient.Defaults.HttpClient{ ??protected override HttpClientHandler CreateHttpClientHandler(){ ? ? ? ?// or return your handlerreturn new WebRequestHandler();} } var config = new HttpApiConfig(new MyHttpClient());var myWebApi = HttpApiClient.Create(config);
如果是外部的HttpClientHandler實例,可以使用如下方式關聯:
var client = new WebApiClient.Defaults.HttpClient(handler);var config = new HttpApiConfig(client);
var myWebApi = HttpApiClient.Create(config);
6. 擴展JsonFormatter
WebApiClient.Defaults.JsonFormatter使用了json.net,每次序列化或反序列化時都會創建JsonSerializerSettings,可以派生WebApiClient.Defaults.JsonFormatter返回自定義的JsonSerializerSettings:
class MyJsonFormatter : WebApiClient.Defaults.JsonFormatter{ ??protected override JsonSerializerSettings CreateSerializerSettings(){ ? ? ?
??return new JsonSerializerSettings{ ? ? ? ? ? ?// your setting};} }
??var config = new HttpApiConfig{ ?
???JsonFormatter = new MyJsonFormatter() };
???var myWebApi = HttpApiClient.Create(config);
7. 擴展WebApiClient.Defaults.KeyValueFormatter
KeyValueFormatter基于Middleware思想,內部由多個轉換器相連組成,隨著轉換器的增加,支持的類型也更多,KeyValueFormatter默認支持序列化以下類型:
1、常用簡單類型及其空類型(byte、int、short、long、doublue、flout、string、decimal、DateTime、Guid、enum、Version和Uri)
2、支持IEnumerable遞歸拆解,默認最多16層
3、KeyValuePair<,>的任意泛型
4、多屬性模型的第一層屬性拆解
如果你需要支持更多的類型,需要派生KeyValueFormatter增加功能:
class MyKeValueFormatter : WebApiClient.Defaults.KeyValueFormatter
{
? ? protected override IEnumerable<ConverterBase> GetConverters()
? ? {
? ? ? ? // 在原有轉換器之前插入DynamicObjectConverter
? ? ? ? var addin = new[] { new DynamicObjectConverter() };
? ? ? ? return addin.Concat(base.GetConverters());
? ? }
}
/// <summary>
/// 表示動態類型轉換器
/// </summary>
class DynamicObjectConverter : ConverterBase
{
? ? /// <summary>
? ? /// 執行轉換
? ? /// </summary>
? ? /// <param name="context">轉換上下文</param>
? ? /// <returns></returns>
? ? public override IEnumerable<KeyValuePair<string, string>> Invoke(ConvertContext context)
? ? {
? ? ? ? var dynamicObject = context.Data as DynamicObject;
? ? ? ? if (dynamicObject != null)
? ? ? ? {
? ? ? ? ? ? return from name in dynamicObject.GetDynamicMemberNames()
? ? ? ? ? ? ? ? ? ?let value = this.GetValue(dynamicObject, name)
? ? ? ? ? ? ? ? ? ?let ctx = new ConvertContext(name, value, context.Depths, context.Options)
? ? ? ? ? ? ? ? ? ?select ctx.ToKeyValuePair();
? ? ? ? }
? ? ? ? return this.Next.Invoke(context);
? ? }
? ? /// <summary>
? ? /// 獲取動態類型的值
? ? /// </summary>
? ? /// <param name="dynamicObject">實例</param>
? ? /// <param name="name">名稱</param>
? ? /// <returns></returns>
? ? private object GetValue(DynamicObject dynamicObject, string name)
? ? {
? ? ? ? object value;
? ? ? ? var binder = new MemberBinder(name);
? ? ? ? dynamicObject.TryGetMember(binder, out value);
? ? ? ? return value;
? ? }
? ? /// <summary>
? ? /// 表示成員值的獲取綁定
? ? /// </summary>
? ? private class MemberBinder : GetMemberBinder
? ? {
? ? ? ? /// <summary>
? ? ? ? /// 鍵的信息獲取綁定
? ? ? ? /// </summary>
? ? ? ? /// <param name="key">鍵名</param>
? ? ? ? public MemberBinder(string key)
? ? ? ? ? ? : base(key, false)
? ? ? ? {
? ? ? ? }
? ? ? ? /// <summary>
? ? ? ? /// 在派生類中重寫時,如果無法綁定目標動態對象,則執行動態獲取成員操作的綁定
? ? ? ? /// </summary>
? ? ? ? /// <param name="target"></param>
? ? ? ? /// <param name="errorSuggestion"></param>
? ? ? ? /// <returns></returns>
? ? ? ? public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
? ? ? ? {
? ? ? ? ? ? throw new NotImplementedException();
? ? ? ? }
? ? }
}
相關內容:?
自動類型安全的REST .NET標準庫refit
WebApi client 的面向切面編程
net的retrofit--WebApiClient庫
.net的retrofit--WebApiClient庫深入篇
原文地址:https://www.cnblogs.com/kewei/p/8302382.html
.NET社區新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com
總結
以上是生活随笔為你收集整理的.net的retrofit--WebApiClient底层篇的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ASP.NET Core中使用IOC三部
- 下一篇: 【直播 】ASP.NET Core解密底