.net core 中 WebApiClientCore的使用
WebApiClient
接口注册与选项
1 配置文件中配置HttpApiOptions选项
配置示例
"IUserApi": {
"HttpHost": "http://www.webappiclient.com/",
"UseParameterPropertyValidate": false,
"UseReturnValuePropertyValidate": false,
"JsonSerializeOptions": {
"IgnoreNullValues": true,
"WriteIndented": false
}
}
2 Service注册
示例
services
.ConfigureHttpApi<IUserApi>(Configuration.GetSection(nameof(IUserApi)))
.ConfigureHttpApi<IUserApi>(o =>
{
// 符合国情的不标准时间格式,有些接口就是这么要求必须不标准
o.JsonSerializeOptions.Converters.Add(new JsonDateTimeConverter("yyyy-MM-dd HH:mm:ss"));
});
HttpApiOptions详细展示
/// <summary>
/// 表示HttpApi选项
/// </summary>
public class HttpApiOptions
{
/// <summary>
/// 获取或设置Http服务完整主机域名
/// 例如http://www.abc.com/或http://www.abc.com/path/
/// 设置了HttpHost值,HttpHostAttribute将失效
/// </summary>
public Uri? HttpHost { get; set; }
/// <summary>
/// 获取或设置是否使用的日志功能
/// </summary>
public bool UseLogging { get; set; } = true;
/// <summary>
/// 获取或设置请求头是否包含默认的UserAgent
/// </summary>
public bool UseDefaultUserAgent { get; set; } = true;
/// <summary>
/// 获取或设置是否对参数的属性值进行输入有效性验证
/// </summary>
public bool . { get; set; } = true;
/// <summary>
/// 获取或设置是否对返回值的属性值进行输入有效性验证
/// </summary>
public bool UseReturnValuePropertyValidate { get; set; } = true;
/// <summary>
/// 获取json序列化选项
/// </summary>
public JsonSerializerOptions JsonSerializeOptions { get; } = CreateJsonSerializeOptions();
/// <summary>
/// 获取json反序列化选项
/// </summary>
public JsonSerializerOptions JsonDeserializeOptions { get; } = CreateJsonDeserializeOptions();
/// <summary>
/// xml序列化选项
/// </summary>
public XmlWriterSettings XmlSerializeOptions { get; } = new XmlWriterSettings();
/// <summary>
/// xml反序列化选项
/// </summary>
public XmlReaderSettings XmlDeserializeOptions { get; } = new XmlReaderSettings();
/// <summary>
/// 获取keyValue序列化选项
/// </summary>
public KeyValueSerializerOptions KeyValueSerializeOptions { get; } = new KeyValueSerializerOptions();
/// <summary>
/// 获取自定义数据存储的字典
/// </summary>
public Dictionary<object, object> Properties { get; } = new Dictionary<object, object>();
/// <summary>
/// 获取接口的全局过滤器集合
/// </summary>
public IList<IApiFilter> GlobalFilters { get; } = new List<IApiFilter>();
/// <summary>
/// 创建序列化JsonSerializerOptions
/// </summary>
private static JsonSerializerOptions CreateJsonSerializeOptions()
{
return new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
}
/// <summary>
/// 创建反序列化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)拼接规则
所有的Uri拼接都是通过Uri(Uri baseUri, Uri relativeUri)这个构造器生成。
带/
结尾的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
不带/
结尾的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
事实上http://a.com
与http://a.com/
是完全一样的,他们的path都是/
,所以才会表现一样。为了避免低级错误的出现,请使用的标准baseUri书写方式,即使用/
作为baseUri的结尾的第一种方式。
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的注册
services.AddTokenProvider<ITestApi,TestTokenProvider>();
OAuthTokenHandler
可以自定义OAuthTokenHandler官方定义是属于http消息处理器,功能与OAuthTokenAttribute一样,除此之外,如果因为意外的原因导致服务器仍然返回未授权(401状态码),其还会丢弃旧token,申请新token来重试一次请求。
OAuthToken在webapiclient中一般是保存在http请求的Header的Authrization
当token在url中时我们需要自定义OAuthTokenHandler
class UriQueryOAuthTokenHandler : OAuthTokenHandler
{
/// <summary>
/// token应用的http消息处理程序
/// </summary>
/// <param name="tokenProvider">token提供者</param>
public UriQueryOAuthTokenHandler(ITokenProvider tokenProvider)
: base(tokenProvider)
{
}
/// <summary>
/// 应用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是请求的的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时要注意OAuthToken特性不要定义在具有请求token的Http请求定义上
Patch请求
json patch是为客户端能够局部更新服务端已存在的资源而设计的一种标准交互,在RFC6902里有详细的介绍json patch,通俗来讲有以下几个要点:
- 使用HTTP PATCH请求方法;
- 请求body为描述多个opration的数据json内容;
- 请求的Content-Type为application/json-patch+json;
声明Patch方法
public interface IUserApi
{
[HttpPatch("api/users/{id}")]
Task<UserInfo> PatchAsync(string id, JsonPatchDocument<User> doc);
}
实例化JsonPatchDocument
var doc = new JsonPatchDocument<User>();
doc.Replace(item => item.Account, "laojiu");
doc.Replace(item => item.Email, "laojiu@qq.com");
请求内容
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)
{
// 请求配置异常
}
catch (HttpRequestException ex) when (ex.InnerException is ApiResponseStatusException statusException)
{
// 响应状态码异常
}
catch (HttpRequestException ex) when (ex.InnerException is ApiException apiException)
{
// 抽象的api异常
}
catch (HttpRequestException ex) when (ex.InnerException is SocketException socketException)
{
// socket连接层异常
}
catch (HttpRequestException ex)
{
// 请求异常
}
catch (Exception ex)
{
// 异常
}
请求重试
使用ITask<>异步声明,就有Retry的扩展,Retry的条件可以为捕获到某种Exception或响应模型符合某种条件。
GetNumberTemplateForEditOutput put = new GetNumberTemplateForEditOutput();
var res = await _testApi.GetForEdit(id).Retry(maxCount: 1).WhenCatchAsync<ApiResponseStatusException>(async p =>
{
if (p.StatusCode == HttpStatusCode.Unauthorized)
{
await Token();//当http请求异常时报错,重新请求一次,保证token一直有效
}
});
put = res.Result;
return put;
API接口处理
使用ITask<>异步声明
[HttpHost("http://wmsapi.dev.gct-china.com/")]//请求地址域名
public interface ITestApi : IHttpApi
{
[OAuthToken]//权限
[JsonReturn]//设置返回格式
[HttpGet("/api/services/app/NumberingTemplate/GetForEdit")]//请求路径
ITask<AjaxResponse<GetNumberTemplateForEditOutput>> GetForEdit([Required] string id);//请求参数声明
[HttpPost("api/TokenAuth/Authenticate")]
ITask<string> RequestToken([JsonContent] AuthenticateModel login);
}
基于WebApiClient的扩展类
扩展类声明
/// <summary>
/// WebApiClient扩展类
/// </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;
}
}
扩展类使用
services.AddWebApiClientHttpWithTokeProvider<ITestApi, TestTokenProvider>();
.net core 中 WebApiClientCore的使用的更多相关文章
- .NET Core中的认证管理解析
.NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...
- ASP.NET Core 中的那些认证中间件及一些重要知识点
前言 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系列(一,二,三)奠定一下基础. 有关于 Authentication 的知识太广,所以本篇介绍几个在 A ...
- Asp.net Core中使用Session
前言 2017年就这么悄无声息的开始了,2017年对我来说又是特别重要的一年. 元旦放假在家写了个Asp.net Core验证码登录, 做demo的过程中遇到两个小问题,第一是在Asp.net Cor ...
- 在ASP.NET Core中使用百度在线编辑器UEditor
在ASP.NET Core中使用百度在线编辑器UEditor 0x00 起因 最近需要一个在线编辑器,之前听人说过百度的UEditor不错,去官网下了一个.不过服务端只有ASP.NET版的,如果是为了 ...
- ASP.NET Core中的依赖注入(1):控制反转(IoC)
ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制,ASP.NET通过定义接口的方式对它们进行了"标准化&qu ...
- ASP.NET Core中的依赖注入(2):依赖注入(DI)
IoC主要体现了这样一种设计思想:通过将一组通用流程的控制从应用转移到框架之中以实现对流程的复用,同时采用"好莱坞原则"是应用程序以被动的方式实现对流程的定制.我们可以采用若干设计 ...
- ASP.NET Core中的依赖注入(3): 服务的注册与提供
在采用了依赖注入的应用中,我们总是直接利用DI容器直接获取所需的服务实例,换句话说,DI容器起到了一个服务提供者的角色,它能够根据我们提供的服务描述信息提供一个可用的服务对象.ASP.NET Core ...
- ASP.NET Core中的依赖注入(4): 构造函数的选择与服务生命周期管理
ServiceProvider最终提供的服务实例都是根据对应的ServiceDescriptor创建的,对于一个具体的ServiceDescriptor对象来说,如果它的ImplementationI ...
- ASP.NET Core 中文文档 第二章 指南(4.6)Controller 方法与视图
原文:Controller methods and views 作者:Rick Anderson 翻译:谢炀(Kiler) 校对:孟帅洋(书缘) .张仁建(第二年.夏) .许登洋(Seay) .姚阿勇 ...
- ASP.NET Core 中文文档 第三章 原理(1)应用程序启动
原文:Application Startup 作者:Steve Smith 翻译:刘怡(AlexLEWIS) 校对:谢炀(kiler398).许登洋(Seay) ASP.NET Core 为你的应用程 ...
随机推荐
- SQL的事务
一.基本概念 事务是数据库区别于文件系统的重要特性之一,当有了事务,就可以让数据库始终保持一致性,同时可以通过事务的机制恢复到某个时间点,保证了提交到数据库的修改不会因为系统崩溃而丢失: 事务只是一个 ...
- 一文讲清楚 JVM Safe Point
大家好,我是树哥. 关于 Safe Point 是 JVM 中很关键的一个概念,但我估计有不少同学不是很懂.于是今天跟大家来深入聊聊 Safe Point,希望通过这篇文章能解答这样几个问题: 什么是 ...
- ARC144 D - AND OR Equation
ARC144 D - AND OR Equation Solution 首先可以猜测和答案仅和每一个二进制位以及\(f(0)\)有关系,不妨把按位\(\operatorname{AND}\)和按位\( ...
- mysql安装教程-window操作系统
1.下载安装包(官网下载) 直达链接:https://dev.mysql.com/downloads/mysql/ 下载后放到指定目录下解压即可(给电脑新手忠告:注意不要放在C盘,养成好习惯,放C盘多 ...
- 一天五道Java面试题----第九天(简述MySQL中索引类型对数据库的性能的影响--------->缓存雪崩、缓存穿透、缓存击穿)
这里是参考B站上的大佬做的面试题笔记.大家也可以去看视频讲解!!! 文章目录 1.简述MySQL中索引类型对数据库的性能的影响 2.RDB和AOF机制 3.Redis的过期键的删除策略 4.Redis ...
- <五>掌握左值引用和初识右值引用
1:C++的引用,引用和指针的区别? 1:从汇编指令角度上看,引用和指针没有区别,引用也是通过地址指针的方式访问指向的内存 int &b=a ; 是需要将a的内存地址取出并存下来, b=20; ...
- 分布式ID生成方案总结整理
目录 1.为什么需要分布式ID? 2.业务系统对分布式ID有什么要求? 3.分布式ID生成方案 3.1 UUID 3.2.数据库自增 3.3.号段模式 3.4. Redis实现 3.4. 雪花算法(S ...
- Spring Boot:自定义 Whitelabel 错误页面
一.概述在本文中,我们将研究如何禁用和自定义 Spring Boot 应用程序的默认错误页面,因为正确的错误处理描述了专业性和质量工作. 2.禁用白标错误页面 首先,让我们看看如何通过将server. ...
- Optional用法与争议点
原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处. 简介 要说Java中什么异常最容易出现,我想NullPointerException一定当仁不让,为了解决这种null值 ...
- java-代码编写规范
命名 变量/方法:小驼峰. mBtnHelloWorld 控件 mBtnTest: 按键 mTvTest:文本