.net?core?中?WebApiClientCore的使用示例代碼
WebApiClient
接口注冊(cè)與選項(xiàng)
1 配置文件中配置HttpApiOptions選項(xiàng)
配置示例
"IUserApi": { "HttpHost": "http://www.webappiclient.com/", "UseParameterPropertyValidate": false, "UseReturnValuePropertyValidate": false, "JsonSerializeOptions": { "IgnoreNullValues": true, "WriteIndented": false } }
2 Service注冊(cè)
示例
services .ConfigureHttpApi<IUserApi>(Configuration.GetSection(nameof(IUserApi))) .ConfigureHttpApi<IUserApi>(o => { // 符合國情的不標(biāo)準(zhǔn)時(shí)間格式,有些接口就是這么要求必須不標(biāo)準(zhǔn) o.JsonSerializeOptions.Converters.Add(new JsonDateTimeConverter("yyyy-MM-dd HH:mm:ss")); });
HttpApiOptions詳細(xì)展示
/// <summary> /// 表示HttpApi選項(xiàng) /// </summary> public class HttpApiOptions { /// <summary> /// 獲取或設(shè)置Http服務(wù)完整主機(jī)域名 /// 例如http://www.abc.com/或http://www.abc.com/path/ /// 設(shè)置了HttpHost值,HttpHostAttribute將失效 /// </summary> public Uri? HttpHost { get; set; } /// <summary> /// 獲取或設(shè)置是否使用的日志功能 /// </summary> public bool UseLogging { get; set; } = true; /// <summary> /// 獲取或設(shè)置請(qǐng)求頭是否包含默認(rèn)的UserAgent /// </summary> public bool UseDefaultUserAgent { get; set; } = true; /// <summary> /// 獲取或設(shè)置是否對(duì)參數(shù)的屬性值進(jìn)行輸入有效性驗(yàn)證 /// </summary> public bool . { get; set; } = true; /// <summary> /// 獲取或設(shè)置是否對(duì)返回值的屬性值進(jìn)行輸入有效性驗(yàn)證 /// </summary> public bool UseReturnValuePropertyValidate { get; set; } = true; /// <summary> /// 獲取json序列化選項(xiàng) /// </summary> public JsonSerializerOptions JsonSerializeOptions { get; } = CreateJsonSerializeOptions(); /// <summary> /// 獲取json反序列化選項(xiàng) /// </summary> public JsonSerializerOptions JsonDeserializeOptions { get; } = CreateJsonDeserializeOptions(); /// <summary> /// xml序列化選項(xiàng) /// </summary> public XmlWriterSettings XmlSerializeOptions { get; } = new XmlWriterSettings(); /// <summary> /// xml反序列化選項(xiàng) /// </summary> public XmlReaderSettings XmlDeserializeOptions { get; } = new XmlReaderSettings(); /// <summary> /// 獲取keyValue序列化選項(xiàng) /// </summary> public KeyValueSerializerOptions KeyValueSerializeOptions { get; } = new KeyValueSerializerOptions(); /// <summary> /// 獲取自定義數(shù)據(jù)存儲(chǔ)的字典 /// </summary> public Dictionary<object, object> Properties { get; } = new Dictionary<object, object>(); /// <summary> /// 獲取接口的全局過濾器集合 /// </summary> public IList<IApiFilter> GlobalFilters { get; } = new List<IApiFilter>(); /// <summary> /// 創(chuàng)建序列化JsonSerializerOptions /// </summary> private static JsonSerializerOptions CreateJsonSerializeOptions() { return new JsonSerializerOptions { PropertyNameCaseInsensitive = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, DictionaryKeyPolicy = JsonNamingPolicy.CamelCase, Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; } /// <summary> /// 創(chuàng)建反序列化JsonSerializerOptions /// </summary> /// <returns></returns> private static JsonSerializerOptions CreateJsonDeserializeOptions() { var options = CreateJsonSerializeOptions(); options.Converters.Add(JsonCompatibleConverter.EnumReader); options.Converters.Add(JsonCompatibleConverter.DateTimeReader); return options; } }
Uri(url)拼接規(guī)則
所有的Uri拼接都是通過Uri(Uri baseUri, Uri relativeUri)這個(gè)構(gòu)造器生成。
帶/
結(jié)尾的baseUri
http://a.com/
+b/c/d
=http://a.com/b/c/d
http://a.com/path1/
+b/c/d
=http://a.com/path1/b/c/d
http://a.com/path1/path2/
+b/c/d
=http://a.com/path1/path2/b/c/d
不帶/
結(jié)尾的baseUri
http://a.com
+b/c/d
=http://a.com/b/c/d
http://a.com/path1
+b/c/d
=http://a.com/b/c/d
http://a.com/path1/path2
+b/c/d
=http://a.com/path1/b/c/d
事實(shí)上http://a.com
與http://a.com/
是完全一樣的,他們的path都是/
,所以才會(huì)表現(xiàn)一樣。為了避免低級(jí)錯(cuò)誤的出現(xiàn),請(qǐng)使用的標(biāo)準(zhǔn)baseUri書寫方式,即使用/
作為baseUri的結(jié)尾的第一種方式。
OAuths&Token
推薦使用自定義TokenProvider
public class TestTokenProvider : TokenProvider { private readonly IConfiguration _configuration; public TestTokenProvider(IServiceProvider services,IConfiguration configuration) : base(services) { _configuration = configuration; } protected override Task<TokenResult> RefreshTokenAsync(IServiceProvider serviceProvider, string refresh_token) { return this.RefreshTokenAsync(serviceProvider, refresh_token); } protected override async Task<TokenResult> RequestTokenAsync(IServiceProvider serviceProvider) { LoginInput login = new LoginInput(); login.UserNameOrEmailAddress = "admin"; login.Password = "bb123456"; var result = await serviceProvider.GetRequiredService<ITestApi>().RequestToken(login).Retry(maxCount: 3); return result; } }
TokenProvider的注冊(cè)
services.AddTokenProvider<ITestApi,TestTokenProvider>();
OAuthTokenHandler
可以自定義OAuthTokenHandler官方定義是屬于http消息處理器,功能與OAuthTokenAttribute一樣,除此之外,如果因?yàn)橐馔獾脑驅(qū)е路?wù)器仍然返回未授權(quán)(401狀態(tài)碼),其還會(huì)丟棄舊token,申請(qǐng)新token來重試一次請(qǐng)求。
OAuthToken在webapiclient中一般是保存在http請(qǐng)求的Header的Authrization
當(dāng)token在url中時(shí)我們需要自定義OAuthTokenHandler
class UriQueryOAuthTokenHandler : OAuthTokenHandler { /// <summary> /// token應(yīng)用的http消息處理程序 /// </summary> /// <param name="tokenProvider">token提供者</param> public UriQueryOAuthTokenHandler(ITokenProvider tokenProvider) : base(tokenProvider) { } /// <summary> /// 應(yīng)用token /// </summary> /// <param name="request"></param> /// <param name="tokenResult"></param> protected override void UseTokenResult(HttpRequestMessage request, TokenResult tokenResult) { // var builder = new UriBuilder(request.RequestUri); // builder.Query += "mytoken=" + Uri.EscapeDataString(tokenResult.Access_token); // request.RequestUri = builder.Uri; var uriValue = new UriValue(request.RequestUri).AddQuery("myToken", tokenResult.Access_token); request.RequestUri = uriValue.ToUri(); } }
AddQuery是請(qǐng)求的的url中攜帶token的key
自定義OAuthTokenHandler的使用
services .AddHttpApi<IUserApi>() .AddOAuthTokenHandler((s, tp) => new UriQueryOAuthTokenHandler(tp)); //自定義TokoenProvider使用自定義OAuthTokenHandler apiBulider.AddOAuthTokenHandler<UrlTokenHandler>((sp,token)=> { token=sp.GetRequiredService<TestTokenProvider>(); return new UrlTokenHandler(token); },WebApiClientCore.Extensions.OAuths.TypeMatchMode.TypeOrBaseTypes);
OAuthToken 特性
OAuthToken可以定義在繼承IHttpApi的接口上也可以定義在接口的方法上
在使用自定義TokenProvier時(shí)要注意OAuthToken特性不要定義在具有請(qǐng)求token的Http請(qǐng)求定義上
Patch請(qǐng)求
json patch是為客戶端能夠局部更新服務(wù)端已存在的資源而設(shè)計(jì)的一種標(biāo)準(zhǔn)交互,在RFC6902里有詳細(xì)的介紹json patch,通俗來講有以下幾個(gè)要點(diǎn):
- 使用HTTP PATCH請(qǐng)求方法;
- 請(qǐng)求body為描述多個(gè)opration的數(shù)據(jù)json內(nèi)容;
- 請(qǐng)求的Content-Type為application/json-patch+json;
聲明Patch方法
public interface IUserApi { [HttpPatch("api/users/{id}")] Task<UserInfo> PatchAsync(string id, JsonPatchDocument<User> doc); }
實(shí)例化JsonPatchDocument
var doc = new JsonPatchDocument<User>(); doc.Replace(item => item.Account, "laojiu"); doc.Replace(item => item.Email, "laojiu@qq.com");
請(qǐng)求內(nèi)容
PATCH /api/users/id001 HTTP/1.1 Host: localhost:6000 User-Agent: WebApiClientCore/1.0.0.0 Accept: application/json; q=0.01, application/xml; q=0.01 Content-Type: application/json-patch+json [{"op":"replace","path":"/account","value":"laojiu"},{"op":"replace","path":"/email","value":"laojiu@qq.com"}]
異常處理
try { var model = await api.GetAsync(); } catch (HttpRequestException ex) when (ex.InnerException is ApiInvalidConfigException configException) { // 請(qǐng)求配置異常 } catch (HttpRequestException ex) when (ex.InnerException is ApiResponseStatusException statusException) { // 響應(yīng)狀態(tài)碼異常 } catch (HttpRequestException ex) when (ex.InnerException is ApiException apiException) { // 抽象的api異常 } catch (HttpRequestException ex) when (ex.InnerException is SocketException socketException) { // socket連接層異常 } catch (HttpRequestException ex) { // 請(qǐng)求異常 } catch (Exception ex) { // 異常 }
請(qǐng)求重試
使用ITask<>異步聲明,就有Retry的擴(kuò)展,Retry的條件可以為捕獲到某種Exception或響應(yīng)模型符合某種條件。
GetNumberTemplateForEditOutput put = new GetNumberTemplateForEditOutput(); var res = await _testApi.GetForEdit(id).Retry(maxCount: 1).WhenCatchAsync<ApiResponseStatusException>(async p => { if (p.StatusCode == HttpStatusCode.Unauthorized) { await Token();//當(dāng)http請(qǐng)求異常時(shí)報(bào)錯(cuò),重新請(qǐng)求一次,保證token一直有效 } }); put = res.Result; return put;
API接口處理
使用ITask<>異步聲明
[HttpHost("請(qǐng)求地址")]//請(qǐng)求地址域名 public interface ITestApi : IHttpApi { [OAuthToken]//權(quán)限 [JsonReturn]//設(shè)置返回格式 [HttpGet("/api/services/app/NumberingTemplate/GetForEdit")]//請(qǐng)求路徑 ITask<AjaxResponse<GetNumberTemplateForEditOutput>> GetForEdit([Required] string id);//請(qǐng)求參數(shù)聲明 [HttpPost("api/TokenAuth/Authenticate")] ITask<string> RequestToken([JsonContent] AuthenticateModel login); }
基于WebApiClient的擴(kuò)展類
擴(kuò)展類聲明
/// <summary> /// WebApiClient擴(kuò)展類 /// </summary> public static class WebApiClientExentions { public static IServiceCollection AddWebApiClietHttp<THttp>(this IServiceCollection services, Action<HttpApiOptions>? options = null) where THttp : class, IHttpApi { HttpApiOptions option = new HttpApiOptions(); option.JsonSerializeOptions.Converters.Add(new JsonDateTimeConverter("yyyy-MM-dd HH:mm:ss")); option.UseParameterPropertyValidate = true; if(options != null) { options.Invoke(option); } services.AddHttpApi<THttp>().ConfigureHttpApi(p => p = option); return services; } public static IServiceCollection AddWebApiClietHttp<THttp>(this IServiceCollection services,IConfiguration configuration) where THttp : class, IHttpApi { services.AddHttpApi<THttp>().ConfigureHttpApi((Microsoft.Extensions.Configuration.IConfiguration)configuration); return services; } public static IServiceCollection AddWebApiClientHttpWithTokeProvider<THttp, TTokenProvider>(this IServiceCollection services, Action<HttpApiOptions>? options = null) where THttp : class, IHttpApi where TTokenProvider : class, ITokenProvider { services.AddWebApiClietHttp<THttp>(options); services.AddTokenProvider<THttp,TTokenProvider>(); return services; } public static IServiceCollection AddWebApiClientHttpWithTokeProvider<THttp, TTokenProvider>(this IServiceCollection services, IConfiguration configuration) where THttp : class, IHttpApi where TTokenProvider : class, ITokenProvider { services.AddWebApiClietHttp<THttp>(configuration); services.AddTokenProvider<THttp, TTokenProvider>(); return services; } }
擴(kuò)展類使用
services.AddWebApiClientHttpWithTokeProvider<ITestApi, TestTokenProvider>();
到此這篇關(guān)于.net core 中 WebApiClientCore的使用示例代碼的文章就介紹到這了,更多相關(guān).net core 中 WebApiClientCore使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
ADO.NET實(shí)現(xiàn)對(duì)SQL Server數(shù)據(jù)庫的增刪改查示例
本篇文章主要介紹了ADO.NET實(shí)現(xiàn)對(duì)SQL Server數(shù)據(jù)庫的增刪改查示例,非常具有實(shí)用價(jià)值,需要的朋友可以參考下。2017-01-01利用VS2019創(chuàng)建Web項(xiàng)目并發(fā)送到IIS及IIS與ASP.NET配置教程
這篇文章主要介紹了利用VS2019創(chuàng)建Web項(xiàng)目,并發(fā)送到IIS,以及IIS與ASP.NET配置,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03.NET的DateTime函數(shù)獲取上個(gè)月的起始和截止時(shí)間的方法
這篇文章主要介紹了NET的DateTime函數(shù)獲取上個(gè)月的起始和截止時(shí)間的方法,可廣泛使用于報(bào)表中的時(shí)間自動(dòng)選擇功能,是非常實(shí)用的技巧,需要的朋友可以參考下2015-01-01淺談.NET中加密和解密的實(shí)現(xiàn)方法分享
這篇文章介紹了.NET中加密和解密的實(shí)現(xiàn)方法,有需要的朋友可以參考一下2013-11-11ASP.NET?MVC實(shí)現(xiàn)本地化和全球化
這篇文章介紹了ASP.NET?MVC實(shí)現(xiàn)本地化和全球化的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-10-10ASP.NET Core中間件計(jì)算Http請(qǐng)求時(shí)間示例詳解
這篇文章主要給大家介紹了關(guān)于ASP.NET Core中間件計(jì)算Http請(qǐng)求時(shí)間的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用ASP.NET Core具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06asp.net GridView中超鏈接的使用(帶參數(shù))
在GridView中,點(diǎn)擊鏈接列跳轉(zhuǎn)到指定頁面的實(shí)現(xiàn)代碼,需要的朋友可以參考下。2010-03-03Asp.Net Core控制器如何接收原始請(qǐng)求正文內(nèi)容詳解
這篇文章主要給大家介紹了關(guān)于Asp.Net Core控制器如何接收原始請(qǐng)求正文內(nèi)容的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09