日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

.net的retrofit--WebApiClient库深入篇

發(fā)布時(shí)間:2023/12/4 编程问答 59 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .net的retrofit--WebApiClient库深入篇 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

本篇文章的內(nèi)容是對(duì)上一篇.net的retrofit--WebApiClient庫(kù)的深層次補(bǔ)充,你可能需要先閱讀上一篇才能理解此篇文章。本文將詳細(xì)地講解WebApiClient的原理,結(jié)合實(shí)際項(xiàng)目中可能遇到的問題進(jìn)行使用說(shuō)明。

庫(kù)簡(jiǎn)介

WebApiClient是開源在github上的一個(gè)httpClient客戶端庫(kù),內(nèi)部基于HttpClient開發(fā),是一個(gè)只需要定義c#接口(interface),并打上相關(guān)特性,即可異步調(diào)用http-api的框架 ,支持.net framework4.5+、netcoreapp2.0和netstandard2.0。

1. HttpApiConfig的使用

1.1 創(chuàng)建HttpApiConfig

var config = new HttpApiConfig { ? ?// 請(qǐng)求的域名,會(huì)覆蓋[HttpHost]特性HttpHost = new Uri("http://www.webapiclient.com"), };
var myWebApi = HttpApiClient.Create<MyWebApi>(config);

1.2 HttpApiConfig.FormatOptions

當(dāng)序列化一個(gè)多屬性的模型時(shí),FormatOptions可以約束DateTime類型的屬性值轉(zhuǎn)換為字符串的格式,也可以指定屬性名是為CamelCase。

1.3 HttpApiConfig.HttpClient

首次獲取HttpClient實(shí)例時(shí),HttpClient的實(shí)例將被創(chuàng)建,HttpClient屬性是一個(gè)IHttpClient接口,是對(duì)HttpClient對(duì)象的包裝,它的Handler暴露出與HttpClient關(guān)聯(lián)的HttpClientHandler對(duì)象。

1.4 HttpApiConfig.GlobalFilters

GlobalFilters用于添加全局過濾器,這些過濾器不需要使用硬編碼修飾于接口,而是通過配置傳輸給接口的實(shí)例,適用于接口定義的項(xiàng)目和接口調(diào)用的項(xiàng)目分離開的項(xiàng)目結(jié)構(gòu)。

1.5 HttpApiConfig的生命周期

  • 在實(shí)例化HttpApiConfig之后,當(dāng)不再使用時(shí),應(yīng)該顯性地調(diào)用Dispose釋放資源;

  • 對(duì)于1.1的例子,如果myWebApi實(shí)現(xiàn)了IDisposable接口,調(diào)用myWebApi.Dispose()也會(huì)將HttpApiConfig的HttpClient屬性也釋放;

  • 對(duì)于var myWebApi = HttpApiClient.Create

2.WebApiClient執(zhí)行流程

  • 1 創(chuàng)建接口實(shí)現(xiàn)類

    當(dāng)調(diào)用WebApiClient.Create時(shí),內(nèi)部使用Emit創(chuàng)建接口的實(shí)現(xiàn)類,該實(shí)現(xiàn)類為接口的每個(gè)方法實(shí)現(xiàn)為:獲取方法信息和調(diào)用參數(shù)值傳給攔截器(IApiInterceptor)處理;

  • 2 攔截器創(chuàng)建ITask任務(wù)

    IApiInterceptor收到方法的調(diào)用時(shí),根據(jù)方法信息和參數(shù)值創(chuàng)建Api描述對(duì)象ApiActionDescriptor,然后將和HttpApiConfig實(shí)例和ApiActionDescriptor包裝成ITask任務(wù)對(duì)象并返回;

  • 3 等待調(diào)用者執(zhí)行請(qǐng)求

    當(dāng)調(diào)用者await ITask 或 await ITask.InvokeAsync()時(shí),創(chuàng)建ApiActionContext并按照順序執(zhí)行ApiActionContext里描述的各種Attribute,這些Attribue影響著ApiActionContext的HttpRequestMessage等屬性對(duì)象,然后使用HttpClient發(fā)送這個(gè)HttpRequestMessage對(duì)象,得到HttpResponseMessage,最后將HttpResponseMessage的Content轉(zhuǎn)換為接口的返回值;

/// <summary>

/// 異步執(zhí)行api

/// </summary>

/// <param name="context">上下文</param>

/// <returns></returns>

public async Task<object> ExecuteAsync(ApiActionContext context)

{

? ? var apiAction = context.ApiActionDescriptor;

? ? var globalFilters = context.HttpApiConfig.GlobalFilters;


? ? 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 globalFilters)

? ? {

? ? ? ? await filter.OnBeginRequestAsync(context);

? ? }


? ? foreach (var filter in apiAction.Filters)

? ? {

? ? ? ? await filter.OnBeginRequestAsync(context);

? ? }


? ? await this.SendAsync(context);


? ? foreach (var filter in globalFilters)

? ? {

? ? ? ? await filter.OnEndRequestAsync(context);

? ? }


? ? foreach (var filter in apiAction.Filters)

? ? {

? ? ? ? await filter.OnEndRequestAsync(context);

? ? }


? ? return await apiAction.Return.Attribute.GetTaskResult(context);

}

3.使用自定義特性

WebApiClient內(nèi)置很多特性,包含接口級(jí)、方法級(jí)、參數(shù)級(jí)的,他們分別是實(shí)現(xiàn)了IApiActionAttribute接口、IApiActionFilterAttribute接口、IApiParameterAttribute接口、IApiParameterable接口和IApiReturnAttribute接口的一個(gè)或多個(gè)接口。一般情況下內(nèi)置的特性就足以夠用,但實(shí)際項(xiàng)目中,你可能會(huì)遇到個(gè)別特殊的場(chǎng)景,需要自己實(shí)現(xiàn)一些特性或過濾器,主要用來(lái)操控請(qǐng)求上下文的RequestMessage對(duì)象,影響請(qǐng)求對(duì)象。

3.1 自定義IApiParameterAttribute例子

舉個(gè)例子:比如,服務(wù)端要求使用x-www-form-urlencoded提交,由于接口設(shè)計(jì)不合理,目前要求是提交:fieldX= {X}的json文本&fieldY={Y}的json文本 這里{X}和{Y}都是一個(gè)多字段的Model,我們對(duì)應(yīng)的接口是這樣設(shè)計(jì)的:

[HttpHost("/upload")]ITask<bool> UploadAsync([FormField]
[AliasAs("fieldX")]
string xJson,[FormField][AliasAs("fieldY")]
string yJson);

顯然,我們接口參數(shù)為string類型的范圍太廣,沒有約束性,我們希望是這樣子:

[HttpHost("/upload")]
ITask<bool> UploadAsync([FormFieldJson] X fieldX, [FormFieldJson] Y fieldY);

現(xiàn)在我們?yōu)檫@種特殊場(chǎng)景實(shí)現(xiàn)一個(gè)[FormFieldJson]的參數(shù)級(jí)特性,給每個(gè)參數(shù)修飾這個(gè)[FormFieldJson]后,參數(shù)就解釋為其序列化為Json的文本,做為表單的一個(gè)字段內(nèi)容:

[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]

class FormFieldJson: Attribute, IApiParameterAttribute

{

? ? public async Task BeforeRequestAsync(ApiActionContext context, ApiParameterDescriptor parameter)

? ? {

? ? ? ? var options = context.HttpApiConfig.FormatOptions;

? ? ? ? var json = context.HttpApiConfig.JsonFormatter.Serialize(parameter.Value, options);

? ? ? ? var fieldName = parameter.Name;

? ? ? ? await context.RequestMessage.AddFormFieldAsync(fieldName, json);

? ? }

}

3.2 自定義過濾器

舉個(gè)例子:我們需要為每個(gè)請(qǐng)求的url額外的動(dòng)態(tài)添加一個(gè)叫sign的參數(shù),這個(gè)sign可能和配置文件等有關(guān)系,而且每次都需要計(jì)算:

class SignFilter : ApiActionFilterAttribute

{

? ? public override Task OnBeginRequestAsync(ApiActionContext context)

? ? {

? ? ? ? var sign = DateTime.Now.Ticks.ToString();

? ? ? ? context.RequestMessage.AddUrlQuery("sign", sign);

? ? ? ? return base.OnBeginRequestAsync(context);

? ? }

}


[SignFilter]

public interface MyApi : IDisposable

{

? ? ...

}

3.3 自定義全局過濾器

class GlobalFilter : IApiActionFilter

{

? ? public Task OnBeginRequestAsync(ApiActionContext context)

? ? {

? ? ? ? if (context.ApiActionDescriptor.Member.IsDefined(typeof(MyCustomAttribute), true))

? ? ? ? {

? ? ? ? ? ? // do something

? ? ? ? }

? ? ? ? return Task.CompletedTask;

? ? }


? ? public Task OnEndRequestAsync(ApiActionContext context)

? ? {

? ? ? ? return Task.CompletedTask;

? ? }

}


// 通過配置項(xiàng)將全局過濾器傳給MyWebApi實(shí)例

var config = new HttpApiConfig();

config.GlobalFilters.Add(new GlobalFilter());

var myWebApi = HttpApiClient.Create<MyWebApi>(config);

4. DataAnnotations

在一些場(chǎng)景中,你的模型與服務(wù)需要的數(shù)據(jù)模塊可能不是全部吻合,DataAnnotations的功能可以非常方便實(shí)現(xiàn)兩者的對(duì)接,目前DataAnnotations只支持Json序列化和KeyValue序列化,xml序列化不受任何變化。

public class UserInfo

{

? ? public string Account { get; set; }


? ? // 別名

? ? [AliasAs("a_password")]

? ? public string Password { get; set; }


? ? // 時(shí)間格式,優(yōu)先級(jí)最高

? ? [DateTimeFormat("yyyy-MM-dd")]

? ? public DateTime? BirthDay { get; set; }

? ??

? ? // 忽略序列化

? ? [IgnoreSerialized]

? ? public string Email { get; set; }?

? ??

? ? // 時(shí)間格式

? ? [DateTimeFormat("yyyy-MM-dd HH:mm:ss")]

? ? public DateTime CreateTime { get; set; }

}

5. 了解ITask對(duì)象

5.1 await ITask

await ITask,實(shí)際是調(diào)用了ITask.GetAwaiter()方法,等于同于ITask.InvokeAsync().GetAwaiter()方法。所以await ITask等同于await ITask.InvokeAsync()

5.2 ITask的InvokeAsync方法

InvokeAsync()返回Task對(duì)象,實(shí)際是http請(qǐng)求的任務(wù)對(duì)象。一個(gè)ITask實(shí)例,可以多次調(diào)用InvokeAsync()方法,完成多次一模一樣的請(qǐng)求。ITask的很多擴(kuò)展,是對(duì)InvokeAsync方法調(diào)用的包裝而得到。

5.3 ITask的Retry和Handle

Retry本質(zhì)上是對(duì)ITask的InvokeAsync的包裝,實(shí)際思想是當(dāng)符合某種條件時(shí),就多調(diào)用一次InvokeAsync方法,達(dá)到重試提交請(qǐng)求的目的。
Handle也是對(duì)ITask的InvokeAsync的包裝,使用try catch對(duì)InvokeAsync方法封裝為新的委托,當(dāng)捕獲到符合條件的異常類型時(shí),就返回某種結(jié)果。

var result = await myWebApi.TestAsync().Retry(3, i => TimeSpan.FromSeconds(i)).WhenCatch<Exception>().HandleAsDefaultWhenException();

以上可以解讀為,當(dāng)遇到異常時(shí),再重試請(qǐng)求,累計(jì)重試3次還是異常的話,處理為返回null值,期間總共最多請(qǐng)求了4次。

5.4 同步請(qǐng)求

HttpClient目前沒提供任何的同步請(qǐng)求方法,所以WebApiClient的請(qǐng)求也是一樣,如果遇到必須使用同步的場(chǎng)景,可以暫時(shí)使用 ITask.GetAwaiter().GetResult()方法等待結(jié)果。

相關(guān)內(nèi)容:?

  • 自動(dòng)類型安全的REST .NET標(biāo)準(zhǔn)庫(kù)refit

  • WebApi client 的面向切面編程

  • net的retrofit--WebApiClient庫(kù)

原文地址:https://www.cnblogs.com/kewei/p/8302382.html


.NET社區(qū)新聞,深度好文,歡迎訪問公眾號(hào)文章匯總 http://www.csharpkit.com

總結(jié)

以上是生活随笔為你收集整理的.net的retrofit--WebApiClient库深入篇的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。