设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间01 现在时间01 缓存数据 当你走完一段之后回头看,你会发现,那些真正能被记得的事真的是没有多少,真正无法忘记的人屈指可数,真正有趣的日子不过是那么一些,而真正需要害怕的也是寥寥无几。

当你走完一段之后回头看,你会发现,那些真正能被记得的事真的是没有多少,真正无法忘记的人屈指可数,真正有趣的日子不过是那么一些,而真正需要害怕的也是寥寥无几。

查看: 1590|回复: 2

.net core 中 WebApiClientCore的使用示例代码

[复制链接]

  离线 

TA的专栏

  • 打卡等级:热心大叔
  • 打卡总天数:230
  • 打卡月天数:0
  • 打卡总奖励:3436
  • 最近打卡:2025-11-20 05:39:00
等级头衔

等級:晓枫资讯-上等兵

在线时间
0 小时

积分成就
威望
0
贡献
399
主题
371
精华
0
金钱
4651
积分
834
注册时间
2023-1-5
最后登录
2025-11-20

发表于 2023-2-26 20:37:25 | 显示全部楼层 |阅读模式

WebApiClient

接口注册与选项

1 配置文件中配置HttpApiOptions选项

配置示例

  1. "IUserApi": {
  2. "HttpHost": "http://www.webappiclient.com/",
  3. "UseParameterPropertyValidate": false,
  4. "UseReturnValuePropertyValidate": false,
  5. "JsonSerializeOptions": {
  6. "IgnoreNullValues": true,
  7. "WriteIndented": false
  8. }
  9. }
复制代码

2 Service注册

示例

  1. services
  2. .ConfigureHttpApi<IUserApi>(Configuration.GetSection(nameof(IUserApi)))
  3. .ConfigureHttpApi<IUserApi>(o =>
  4. {
  5. // 符合国情的不标准时间格式,有些接口就是这么要求必须不标准
  6. o.JsonSerializeOptions.Converters.Add(new JsonDateTimeConverter("yyyy-MM-dd HH:mm:ss"));
  7. });
复制代码

HttpApiOptions详细展示

  1. /// <summary>
  2. /// 表示HttpApi选项
  3. /// </summary>
  4. public class HttpApiOptions
  5. {
  6. /// <summary>
  7. /// 获取或设置Http服务完整主机域名
  8. /// 例如http://www.abc.com/或http://www.abc.com/path/
  9. /// 设置了HttpHost值,HttpHostAttribute将失效
  10. /// </summary>
  11. public Uri? HttpHost { get; set; }
  12. /// <summary>
  13. /// 获取或设置是否使用的日志功能
  14. /// </summary>
  15. public bool UseLogging { get; set; } = true;
  16. /// <summary>
  17. /// 获取或设置请求头是否包含默认的UserAgent
  18. /// </summary>
  19. public bool UseDefaultUserAgent { get; set; } = true;
  20. /// <summary>
  21. /// 获取或设置是否对参数的属性值进行输入有效性验证
  22. /// </summary>
  23. public bool . { get; set; } = true;
  24. /// <summary>
  25. /// 获取或设置是否对返回值的属性值进行输入有效性验证
  26. /// </summary>
  27. public bool UseReturnValuePropertyValidate { get; set; } = true;
  28. /// <summary>
  29. /// 获取json序列化选项
  30. /// </summary>
  31. public JsonSerializerOptions JsonSerializeOptions { get; } = CreateJsonSerializeOptions();
  32. /// <summary>
  33. /// 获取json反序列化选项
  34. /// </summary>
  35. public JsonSerializerOptions JsonDeserializeOptions { get; } = CreateJsonDeserializeOptions();
  36. /// <summary>
  37. /// xml序列化选项
  38. /// </summary>
  39. public XmlWriterSettings XmlSerializeOptions { get; } = new XmlWriterSettings();
  40. /// <summary>
  41. /// xml反序列化选项
  42. /// </summary>
  43. public XmlReaderSettings XmlDeserializeOptions { get; } = new XmlReaderSettings();
  44. /// <summary>
  45. /// 获取keyValue序列化选项
  46. /// </summary>
  47. public KeyValueSerializerOptions KeyValueSerializeOptions { get; } = new KeyValueSerializerOptions();
  48. /// <summary>
  49. /// 获取自定义数据存储的字典
  50. /// </summary>
  51. public Dictionary<object, object> Properties { get; } = new Dictionary<object, object>();
  52. /// <summary>
  53. /// 获取接口的全局过滤器集合
  54. /// </summary>
  55. public IList<IApiFilter> GlobalFilters { get; } = new List<IApiFilter>();
  56. /// <summary>
  57. /// 创建序列化JsonSerializerOptions
  58. /// </summary>
  59. private static JsonSerializerOptions CreateJsonSerializeOptions()
  60. {
  61. return new JsonSerializerOptions
  62. {
  63. PropertyNameCaseInsensitive = true,
  64. PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
  65. DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
  66. Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
  67. };
  68. }
  69. /// <summary>
  70. /// 创建反序列化JsonSerializerOptions
  71. /// </summary>
  72. /// <returns></returns>
  73. private static JsonSerializerOptions CreateJsonDeserializeOptions()
  74. {
  75. var options = CreateJsonSerializeOptions();
  76. options.Converters.Add(JsonCompatibleConverter.EnumReader);
  77. options.Converters.Add(JsonCompatibleConverter.DateTimeReader);
  78. return options;
  79. }
  80. }
复制代码

Uri(url)拼接规则

所有的Uri拼接都是通过Uri(Uri baseUri, Uri relativeUri)这个构造器生成。

  1. /
复制代码
结尾的baseUri

    1. http://a.com/
    复制代码
     + 
    1. b/c/d
    复制代码
     = 
    1. http://a.com/b/c/d
    复制代码
    1. http://a.com/path1/
    复制代码
     + 
    1. b/c/d
    复制代码
     = 
    1. http://a.com/path1/b/c/d
    复制代码
    1. http://a.com/path1/path2/
    复制代码
     + 
    1. b/c/d
    复制代码
     = 
    1. http://a.com/path1/path2/b/c/d
    复制代码

不带

  1. /
复制代码
结尾的baseUri

    1. http://a.com
    复制代码
     + 
    1. b/c/d
    复制代码
     = 
    1. http://a.com/b/c/d
    复制代码
    1. http://a.com/path1
    复制代码
     + 
    1. b/c/d
    复制代码
     = 
    1. http://a.com/b/c/d
    复制代码
    1. http://a.com/path1/path2
    复制代码
     + 
    1. b/c/d
    复制代码
     = 
    1. http://a.com/path1/b/c/d
    复制代码

事实上

  1. http://a.com
复制代码
  1. http://a.com/
复制代码
是完全一样的,他们的path都是
  1. /
复制代码
,所以才会表现一样。为了避免低级错误的出现,请使用的标准baseUri书写方式,即使用
  1. /
复制代码
作为baseUri的结尾的第一种方式。

OAuths&Token

推荐使用自定义TokenProvider

  1. public class TestTokenProvider : TokenProvider
  2. {
  3. private readonly IConfiguration _configuration;
  4. public TestTokenProvider(IServiceProvider services,IConfiguration configuration) : base(services)
  5. {
  6. _configuration = configuration;
  7. }
  8. protected override Task<TokenResult> RefreshTokenAsync(IServiceProvider serviceProvider, string refresh_token)
  9. {
  10. return this.RefreshTokenAsync(serviceProvider, refresh_token);
  11. }
  12. protected override async Task<TokenResult> RequestTokenAsync(IServiceProvider serviceProvider)
  13. {
  14. LoginInput login = new LoginInput();
  15. login.UserNameOrEmailAddress = "admin";
  16. login.Password = "bb123456";
  17. var result = await serviceProvider.GetRequiredService<ITestApi>().RequestToken(login).Retry(maxCount: 3);
  18. return result;
  19. }
  20. }
复制代码

TokenProvider的注册

  1. services.AddTokenProvider<ITestApi,TestTokenProvider>();
复制代码

OAuthTokenHandler

可以自定义OAuthTokenHandler官方定义是属于http消息处理器,功能与OAuthTokenAttribute一样,除此之外,如果因为意外的原因导致服务器仍然返回未授权(401状态码),其还会丢弃旧token,申请新token来重试一次请求。

OAuthToken在webapiclient中一般是保存在http请求的Header的Authrization

当token在url中时我们需要自定义OAuthTokenHandler

  1. class UriQueryOAuthTokenHandler : OAuthTokenHandler
  2. {
  3. /// <summary>
  4. /// token应用的http消息处理程序
  5. /// </summary>
  6. /// <param name="tokenProvider">token提供者</param>
  7. public UriQueryOAuthTokenHandler(ITokenProvider tokenProvider)
  8. : base(tokenProvider)
  9. {
  10. }
  11. /// <summary>
  12. /// 应用token
  13. /// </summary>
  14. /// <param name="request"></param>
  15. /// <param name="tokenResult"></param>
  16. protected override void UseTokenResult(HttpRequestMessage request, TokenResult tokenResult)
  17. {
  18. // var builder = new UriBuilder(request.RequestUri);
  19. // builder.Query += "mytoken=" + Uri.EscapeDataString(tokenResult.Access_token);
  20. // request.RequestUri = builder.Uri;
  21. var uriValue = new UriValue(request.RequestUri).AddQuery("myToken", tokenResult.Access_token);
  22. request.RequestUri = uriValue.ToUri();
  23. }
  24. }
复制代码

AddQuery是请求的的url中携带token的key

自定义OAuthTokenHandler的使用

  1. services
  2. .AddHttpApi<IUserApi>()
  3. .AddOAuthTokenHandler((s, tp) => new UriQueryOAuthTokenHandler(tp));
  4. //自定义TokoenProvider使用自定义OAuthTokenHandler
  5. apiBulider.AddOAuthTokenHandler<UrlTokenHandler>((sp,token)=>
  6. {
  7. token=sp.GetRequiredService<TestTokenProvider>();
  8. return new UrlTokenHandler(token);
  9. },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方法

  1. public interface IUserApi
  2. {
  3. [HttpPatch("api/users/{id}")]
  4. Task<UserInfo> PatchAsync(string id, JsonPatchDocument<User> doc);
  5. }
复制代码

实例化JsonPatchDocument

  1. var doc = new JsonPatchDocument<User>();
  2. doc.Replace(item => item.Account, "laojiu");
  3. doc.Replace(item => item.Email, "laojiu@qq.com");
复制代码

请求内容

  1. PATCH /api/users/id001 HTTP/1.1
  2. Host: localhost:6000
  3. User-Agent: WebApiClientCore/1.0.0.0
  4. Accept: application/json; q=0.01, application/xml; q=0.01
  5. Content-Type: application/json-patch+json
  6. [{"op":"replace","path":"/account","value":"laojiu"},{"op":"replace","path":"/email","value":"laojiu@qq.com"}]
复制代码

异常处理

  1. try
  2. {
  3. var model = await api.GetAsync();
  4. }
  5. catch (HttpRequestException ex) when (ex.InnerException is ApiInvalidConfigException configException)
  6. {
  7. // 请求配置异常
  8. }
  9. catch (HttpRequestException ex) when (ex.InnerException is ApiResponseStatusException statusException)
  10. {
  11. // 响应状态码异常
  12. }
  13. catch (HttpRequestException ex) when (ex.InnerException is ApiException apiException)
  14. {
  15. // 抽象的api异常
  16. }
  17. catch (HttpRequestException ex) when (ex.InnerException is SocketException socketException)
  18. {
  19. // socket连接层异常
  20. }
  21. catch (HttpRequestException ex)
  22. {
  23. // 请求异常
  24. }
  25. catch (Exception ex)
  26. {
  27. // 异常
  28. }
复制代码

请求重试

使用ITask<>异步声明,就有Retry的扩展,Retry的条件可以为捕获到某种Exception或响应模型符合某种条件。

  1. GetNumberTemplateForEditOutput put = new GetNumberTemplateForEditOutput();
  2. var res = await _testApi.GetForEdit(id).Retry(maxCount: 1).WhenCatchAsync<ApiResponseStatusException>(async p =>
  3. {
  4. if (p.StatusCode == HttpStatusCode.Unauthorized)
  5. {
  6. await Token();//当http请求异常时报错,重新请求一次,保证token一直有效
  7. }
  8. });
  9. put = res.Result;
  10. return put;
复制代码

API接口处理

使用ITask<>异步声明

  1. [HttpHost("请求地址")]//请求地址域名
  2. public interface ITestApi : IHttpApi
  3. {
  4. [OAuthToken]//权限
  5. [JsonReturn]//设置返回格式
  6. [HttpGet("/api/services/app/NumberingTemplate/GetForEdit")]//请求路径
  7. ITask<AjaxResponse<GetNumberTemplateForEditOutput>> GetForEdit([Required] string id);//请求参数声明
  8. [HttpPost("api/TokenAuth/Authenticate")]
  9. ITask<string> RequestToken([JsonContent] AuthenticateModel login);
  10. }
复制代码

基于WebApiClient的扩展类

扩展类声明

  1. /// <summary>
  2. /// WebApiClient扩展类
  3. /// </summary>
  4. public static class WebApiClientExentions
  5. {
  6. public static IServiceCollection AddWebApiClietHttp<THttp>(this IServiceCollection services, Action<HttpApiOptions>? options = null) where THttp : class, IHttpApi
  7. {
  8. HttpApiOptions option = new HttpApiOptions();
  9. option.JsonSerializeOptions.Converters.Add(new JsonDateTimeConverter("yyyy-MM-dd HH:mm:ss"));
  10. option.UseParameterPropertyValidate = true;
  11. if(options != null)
  12. {
  13. options.Invoke(option);
  14. }
  15. services.AddHttpApi<THttp>().ConfigureHttpApi(p => p = option);
  16. return services;
  17. }
  18. public static IServiceCollection AddWebApiClietHttp<THttp>(this IServiceCollection services,IConfiguration configuration) where THttp : class, IHttpApi
  19. {
  20. services.AddHttpApi<THttp>().ConfigureHttpApi((Microsoft.Extensions.Configuration.IConfiguration)configuration);
  21. return services;
  22. }
  23. public static IServiceCollection AddWebApiClientHttpWithTokeProvider<THttp, TTokenProvider>(this IServiceCollection services, Action<HttpApiOptions>? options = null) where THttp : class, IHttpApi
  24. where TTokenProvider : class, ITokenProvider
  25. {
  26. services.AddWebApiClietHttp<THttp>(options);
  27. services.AddTokenProvider<THttp,TTokenProvider>();
  28. return services;
  29. }
  30. public static IServiceCollection AddWebApiClientHttpWithTokeProvider<THttp, TTokenProvider>(this IServiceCollection services, IConfiguration configuration) where THttp : class, IHttpApi
  31. where TTokenProvider : class, ITokenProvider
  32. {
  33. services.AddWebApiClietHttp<THttp>(configuration);
  34. services.AddTokenProvider<THttp, TTokenProvider>();
  35. return services;
  36. }
  37. }
复制代码

扩展类使用

  1. services.AddWebApiClientHttpWithTokeProvider<ITestApi, TestTokenProvider>();
复制代码

到此这篇关于.net core 中 WebApiClientCore的使用示例代码的文章就介绍到这了,更多相关.net core 中 WebApiClientCore使用内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
-2
主题
4
精华
0
金钱
64
积分
27
注册时间
2022-12-21
最后登录
2023-6-23

发表于 2025-7-13 02:02:37 | 显示全部楼层
感谢楼主,顶。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
17
积分
15
注册时间
2022-12-25
最后登录
2022-12-25

发表于 2025-7-25 09:01:45 | 显示全部楼层
感谢楼主分享。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼
3楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表