C# 使用 REST API HTTP 客户端生成器

本文内容

  1. 使用 AutoClientAttribute
  2. 使用谓词属性定义 HTTP 方法
  3. HTTP 有效负载
  4. HTTP 头

显示另外 2 个

 备注

此 API 是实验性的。 它可能会在后续版本的库中更改,并且无法保证向后兼容性。

HttpClient是使用 REST API 的好方法,但存在挑战。 其中一个挑战是需要写入以使用 API 的样板代码量。 本文介绍了如何使用Microsoft.Extensions.Http.AutoClient NuGet 包修饰接口并生成 HTTP 客户端依赖项。 AutoClient 的基础源生成器生成接口的实现,以及用于将其注册到依赖项注入容器中的扩展方法。 此外,AutoClient 会为每个 HTTP 请求生成遥测数据,该请求随Microsoft.Extensions.Http.Telemetry一起发送。

使用 AutoClientAttribute

AutoClientAttribute负责触发 AutoClient 生成器以发出修饰接口的相应实现。 它接受要从IHttpClientFactory中检索的HttpClient的httpClientName。 请考虑以下接口定义:

C#复制

using Microsoft.Extensions.Http.AutoClient;[AutoClient(httpClientName: "GeneratedClient")]
public interface IProductClient
{
}

 提示

接口名称必须以I开头。 该名称去除了前导I,并用作遥测RequestMetadata的RequestMetadata.DependencyName。 如果名称以ApiClient结尾,则排除这些名称。 例如,如果接口命名为IProductClient,则依赖项名称为Product

要替代计算的依赖项名称,请使用AutoClientAttribute的customDependencyName参数。

C#复制

using Microsoft.Extensions.Http.AutoClient;[AutoClient(httpClientName: "GeneratedClient",customDependencyName: "Widget Service")]
public interface IWidgetClient
{
}

 备注

上述两个代码示例都会导致编译警告,因为接口未定义任何 HTTP 方法。 该警告由 AutoClient 生成器发出,提醒发出实现是无用的。

使用谓词属性定义 HTTP 方法

空接口不是有用的抽象。 要定义 HTTP 方法,必须使用 HTTP 谓词属性。 每个 HTTP 方法都会返回Task<TResult>,其中T是以下类型之一:

返回类型说明
Task<string>响应的原始内容以字符串形式返回。
Task<T>T是任何可序列化的类型时,响应内容从 JSON 反序列化并返回。
Task<HttpResponseMessage>如果需要HttpResponseMessage本身(如从HttpClient.SendAsync中返回),请使用此类型。

当 HTTP 响应的内容类型未application/json且方法的返回类型不是Task<string>时,会引发异常。

HTTP 谓词属性

使用以下属性之一定义 HTTP 方法:

  • Microsoft.Extensions.Http.AutoClient.GetAttribute
  • Microsoft.Extensions.Http.AutoClient.PostAttribute
  • Microsoft.Extensions.Http.AutoClient.PutAttribute
  • Microsoft.Extensions.Http.AutoClient.PatchAttribute
  • Microsoft.Extensions.Http.AutoClient.DeleteAttribute
  • Microsoft.Extensions.Http.AutoClient.HeadAttribute
  • Microsoft.Extensions.Http.AutoClient.OptionsAttribute

每个属性都需要path参数,该参数路由到基础 REST API,并且它应相对于HttpClient.BaseAddress。 path不能包含查询字符串参数,而是使用QueryAttribute。 从遥测的角度来看,path用作RequestMetadata.RequestRoute。

使用任何谓词属性修饰的 HTTP 方法必须具有CancellationToken参数,并且它应是定义的最后一个参数。 CancellationToken参数用于取消 HTTP 请求。

C#复制

using Microsoft.Extensions.Http.AutoClient;[AutoClient("GeneratedClient")]
public interface IUserClient
{[Get("/api/users")]public Task<User[]> GetUsersAsync(CancellationToken cancellationToken = default);
}

前面的代码:

  • 使用GetAttribute定义 HTTP 方法。
  • path 为 /api/users
  • 该方法返回Task<TResult>,其中TUser[]
  • 此方法接受可选的CancellationToken参数,该参数在未提供参数时分配给default

路由参数

URL 可能包含路由参数,例如"/api/users/{userId}"。 要定义路由参数,方法还必须接受名称相同的参数(本例中为userId):

C#复制

using Microsoft.Extensions.Http.AutoClient;[AutoClient(nameof(IRouteParameterUserClient), "User Service")]
public interface IRouteParameterUserClient
{[Get("/api/users/{userId}")]public Task<User> GetUserAsync(string userId,CancellationToken cancellationToken = default);
}

在上述代码中:

  • GetUserAsync方法具有名为userId的路由参数。
  • userId参数用于请求的path,替换{userId}占位符。

遥测请求名称

方法名称用作RequestMetadata.RequestName。 如果方法名称包含Async后缀,会将其删除。 例如,名为GetUsersAsync的方法计算为"GetUsers"

要替代名称,请使用 HTTP 谓词属性的每个属性的RequestName属性。

C#复制

using Microsoft.Extensions.Http.AutoClient;[AutoClient(nameof(IRequestNameUserClient), "User Service")]
public interface IRequestNameUserClient
{[Get("/api/users", RequestName = "CustomRequestName")]public Task<List<User>> GetUsersAsync(CancellationToken cancellationToken = default);
}

HTTP 有效负载

要使用请求发送 HTTP 有效负载,请在方法的参数上使用BodyAttribute。 如果不向其传递任何参数,它会将内容类型视为 JSON,在发送之前对参数进行序列化。 否则,请定义显式BodyContentType并在BodyAttribute内使用它。

C#复制

using Microsoft.Extensions.Http.AutoClient;[AutoClient(nameof(IPayloadUserClient), "User Service")]
public interface IPayloadUserClient
{[Post("/api/users")]public Task<User> CreateUserAsync(// The content type is JSON// The parameter is serialized before sending[Body] User user,CancellationToken cancellationToken = default);[Put("/api/users/{userId}/displayName")]public Task<User> UpdateDisplayNameAsync(string userId,// The content type is text/plain// The parameter is sent as is[Body(BodyContentType.TextPlain)] string displayName,CancellationToken cancellationToken = default);
}

HTTP 头

可通过两种方式使用 HTTP 请求发送标头。 其中一个方式最适合永不更改值的标头(静态标头)。 另一种方式是基于方法的参数更改的标头。

静态标头

要定义静态标头,请在接口定义上使用StaticHeaderAttribute。 将标头名称和值传递给其构造函数。

还可以在方法中一起使用多个StaticHeaderAttribute。 在方法上使用StaticHeader属性时,该 HTTP 标头仅针对该方法发送,而接口级StaticHeader属性针对所有方法发送。

C#复制

using Microsoft.Extensions.Http.AutoClient;[AutoClient(nameof(IStaticHeaderUserClient), "User Service")]
[StaticHeader("X-ForAllRequests", "GlobalHeaderValue")]
public interface IStaticHeaderUserClient
{[Get("/api/users")][StaticHeader("X-ForJustThisRequest", "RequestHeaderValue")]public Task<List<User>> GetUsersAsync(CancellationToken cancellationToken = default);
}

参数标头

使用HeaderAttribute定义基于参数的标头,可以从方法的属性接收标头的值。 将标头名称传递给其构造函数。

该参数可以是任何类型。 当标头类型不是string时,对参数的值调用.ToString()方法。

C#复制

using Microsoft.Extensions.Http.AutoClient;[AutoClient(nameof(IParameterHeaderUserClient), "User Service")]
public interface IParameterHeaderUserClient
{[Get("/api/users")]public Task<List<User>> GetUsersAsync([Header("X-MyHeader")] string myHeader,CancellationToken cancellationToken = default);
}

查询参数

使用方法参数上的QueryAttribute定义查询参数。 所有类型都有效,并且查询值依赖于.ToString()方法,以在不是string类型时获取参数的值。

QueryAttribute.Key从参数的名称分配。

C#复制

using Microsoft.Extensions.Http.AutoClient;[AutoClient(nameof(IQueryUserClient))]
public interface IQueryUserClient
{[Get("/api/users")]public Task<List<User>> GetUsersAsync([Query] string search,CancellationToken cancellationToken = default);
}

GetUsersAsync方法生成 HTTP 请求,其 URL 格式为/api/users?search={search}。 此格式用作遥测的RequestMetadata.RequestRoute。

如果需要更改查询键,可以调用key基于参数的构造函数,QueryAttribute(String)。

C#复制

using Microsoft.Extensions.Http.AutoClient;[AutoClient(nameof(ICustomQueryUserClient))]
public interface ICustomQueryUserClient
{[Get("/api/users")]public Task<List<User>> GetUsersAsync([Query("customQueryKey")] string search,CancellationToken cancellationToken = default);
}

GetUsersAsync方法生成 HTTP 请求(URL 格式类似于/api/users?customQueryKey={customQueryKey}),因为密钥名称被替代为customQueryKey

依赖项注入挂钩

除了接口的实现外,生成扩展方法以在依赖项注入容器中注册客户端。 生成的扩展方法的名称与接口名称相同,将前导I替换为Add

例如,请考虑以下接口定义:

C#复制

using Microsoft.Extensions.Http.AutoClient;[AutoClient(nameof(ICompleteUserClient))]
[StaticHeader("User-Agent", "dotnet-auto-client sample")]
public interface ICompleteUserClient
{[Get("users")]public Task<User[]> GetAllUsersAsync(CancellationToken cancellationToken = default);[Get("users")]public Task<User[]> GetUserByNameAsync([Query] string name,CancellationToken cancellationToken = default);[Get("users/{userId}")]public Task<User> GetUserByIdAsync(int userId,CancellationToken cancellationToken = default);[Post("users")][StaticHeader("X-CustomHeader", "custom-value")]public Task<HttpResponseMessage> CreateUserAsync([Body(BodyContentType.ApplicationJson)] User user,CancellationToken cancellationToken = default);[Delete("user/{userId}")]public Task<User> DeleteUserAsync(int userId,[Header("If-None-Match")] string eTag,CancellationToken cancellationToken = default);
}

虽然生成器发出ICompleteUserClient接口的实现,但它还会在IServiceCollection上生成AddCompleteUserClient扩展方法。 请考虑以下示例Program.cs代码:

C#复制

using System.Text.Json;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;HostApplicationBuilder builder = Host.CreateEmptyApplicationBuilder(null);// Add a named HTTP client "ICompleteUserClient".
builder.Services.AddHttpClient(nameof(ICompleteUserClient), options =>
{options.BaseAddress = new("https://jsonplaceholder.typicode.com");
});builder.Services.AddCompleteUserClient(options =>
{options.JsonSerializerOptions = new(JsonSerializerDefaults.Web){PropertyNameCaseInsensitive = true};
});builder.Services.AddSingleton<UserService>();using IHost host = builder.Build();UserService service = host.Services.GetRequiredService<UserService>();await service.ProcessUsersAsync();host.Run();

在前面的示例代码中:

  • Host.CreateEmptyApplicationBuilder用于创建HostApplicationBuilder。
  • 从HostApplicationBuilder.Services属性中检索IServiceCollection,以调用AddHttpClient(IServiceCollection, String, Action<HttpClient>)扩展方法。
    • 使用要注册的HttpClient的名称和用于配置HttpClient实例的委托调用AddHttpClient扩展方法。
  • 调用AddCompleteUserClient扩展方法以注册ICompleteUserClient接口及其实现。

可以将客户端注入服务构造函数以使用客户端:

C#复制

using System.Net.Http.Json;internal sealed class UserService(ICompleteUserClient userClient)
{public async Task ProcessUsersAsync(){// Create a new user.HttpResponseMessage response = await userClient.CreateUserAsync(new(Id: null, /* Is populated upon successful HTTP POST when creating user */Name: "Ada Lovelace",Username: "ada.lovelace",Email: "1st-computer-programmer@example.com",Address: new(Street: "123 Engineer Lane",Suite: null,City: "London",ZipCode: "EC1A",Geo: new(Lat: 51.509865m, Lng: -0.118092m)),Phone: "+1234567890",Website: "www.example.com",Company: new(Name: "Babbage, LLC.",CatchPhrase: "works on my machine",Bs: "This is the future")));User? createdUser = await response.Content.ReadFromJsonAsync<User>();Console.WriteLine($"""CreateUserAsync: Created user'{createdUser}'...""");// Get user by id.User receivedUser = await userClient.GetUserByIdAsync(7);Console.WriteLine($"""GetUserAsync: Received user'{receivedUser}'...""");// Get list of all users.User[] allUsers = await userClient.GetAllUsersAsync();Console.WriteLine($"""GetUsersAsync: Received a total of {allUsers.Length} users...""");}
}

有关详细信息,请参阅.NET 依赖项注入。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/126555.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CMake基础【学习笔记(八)】

声明此博客为转载 CMake基础 文章目录 CMake基础一、准备知识1.1 C的编译过程1.2 静态链接库和动态链接库1.3 为什么需要CMake1.3.1 g 命令行编译1.3.2 CMake简介 二、CMake基础知识2.1 安装2.2 第一个CMake例子2.3 语法基础2.3.1 指定版本2.3.2 设置项目2.3.3 添加可执行文件…

华纳云 宝塔怎么配置香港服务器多ip?

宝塔面板是一款开源的服务器管理面板&#xff0c;提供了简单易用的图形化界面&#xff0c;使用户能够轻松管理和配置服务器。通过切换到香港服务器多IP&#xff0c;用户可以拥有更多的IP资源&#xff0c;提供更灵活的网络服务。 配置香港服务器多IP 1.登录宝塔面板 打开浏览器&…

Goby 漏洞发布| Cisco IOS XE ebui_wsma_http 接口权限绕过漏洞(CVE-2023-20198)

漏洞名称&#xff1a; Cisco IOS XE ebui_wsma_http 接口权限绕过漏洞&#xff08;CVE-2023-20198&#xff09; English Name&#xff1a; Cisco IOS XE ebui_wsma_http API Permission Bypass Vulnerability (CVE-2023-20198) CVSS core: 10 影响资产数&#xff1a; 307282…

kafka为什么如此之快?

天下武功&#xff0c;唯快不破。同样的&#xff0c;kafka在消息队列领域&#xff0c;也是非常快的&#xff0c;这里的块指的是kafka在单位时间搬运的数据量大小&#xff0c;也就是吞吐量&#xff0c;下图是搬运网上的一个性能测试结果&#xff0c;在同步发送场景下&#xff0c;…

以八数码问题为例实现A*算法的求解(未完结)

八数码&#xff1a; 在一个 33 的网格中&#xff0c;1∼8 这 8 个数字和一个 x 恰好不重不漏地分布在这 33 的网格中。 例如&#xff1a; 1 2 3 x 4 6 7 5 8在游戏过程中&#xff0c;可以把 x 与其上、下、左、右四个方向之一的数字交换&#xff08;如果存在&#xff09;。…

(11月4日)GBASE南大通用 x openGauss Meetup,欢迎报名

由openGauss社区、天津南大通用数据技术股份有限公司主办&#xff0c;伟仕佳杰科技有限公司、神州数码&#xff08;中国&#xff09;有限公司协办的“GBASE南大通用 x openGauss Meetup”活动将于2023年11月4日&#xff08;周六&#xff09;在合肥市高新区云飞路66号天源迪科科…

3DEXPERIENCE云端项目管理小工具--Project Planner项目策划者角色

云端3DEXPERIENCE平台提供了一个协作环境&#xff0c;使企业和个人能够以全新的方式实现创新。它将人员、创意、数据和解决方案连接到一个始终在线且可用的协作和交互环境中&#xff0c;可以帮助您的企业提高执行力、生产率并加速创新。 3DEXPERIENCE中的Project Planner项目策…

BUUCTF 后门查杀 1

BUUCTF:https://buuoj.cn/challenges 题目描述&#xff1a; 小白的网站被小黑攻击了&#xff0c;并且上传了Webshell&#xff0c;你能帮小白找到这个后门么&#xff1f;(Webshell中的密码(md5)即为答案)。 密文&#xff1a; 下载附件&#xff0c;解压得到一个网站文件夹。 解…

Nginx搭载负载均衡及前端项目部署

目录 ​编辑 一.Nginx安装 1.安装所需依赖 2.下载并解压Nginx安装包 3.安装nginx 4.启动Nginx服务 二.Tomcat负载均衡 1.准备环境 1.1 准备两个Tomcat 1.2 修改端口号 1.3 配置Nginx服务器集群 2.效果展示 ​编辑三.前端项目打包 ​编辑四.前端项目部署 1.上传项目…

YOLO目标检测——安全帽佩戴检测数据集【含对应voc、coco和yolo三种格式标签】

实际项目应用&#xff1a;安全帽佩戴检测数据集可以用于实时检测工作人员是否按照要求佩戴了安全帽&#xff0c;以保障他们的安全数据集说明&#xff1a;安全帽佩戴检测数据集&#xff0c;真实场景的高质量图片数据&#xff0c;数据场景丰富&#xff0c;图片分为带头盔和没带头…

云原生周刊:ingress2gateway 发布 | 2023.10.30

开源项目推荐 m9sweeper m9sweeper 是一个免费且简单的 Kubernetes 安全平台。它将行业标准的开源实用程序集成到一站式 Kubernetes 安全工具中&#xff0c;该工具可以帮助大多数 Kubernetes 管理员保护 Kubernetes 集群以及集群上运行的应用程序。 Kairos Kairos 是在 Kub…

wordpress如何修改数据库里用户ID下一个自增值的开始数字

有时候我们为了让别人认为网站有很多注册用户&#xff0c;会想把网站用户ID的起始数改大一点&#xff0c;因为WP默认的用户ID是从1开始&#xff0c;注册一个就加1&#xff0c;这样别人就很容易知道网站的用户量。 那么如何改呢&#xff1f;首先进phpmyadmin&#xff0c;找到wp…

智慧矿山:AI算法在带式运输机中的异物识别应用

随着现代农业和工业的发展&#xff0c;带式运输机在各种生产作业中发挥着越来越重要的作用。然而&#xff0c;在带式运输机运行过程中&#xff0c;可能会混入各种异物&#xff0c;这些异物的存在可能会对运输过程和设备本身造成损害。为了解决这一问题&#xff0c;本文将介绍一…

c++装饰器模式

前言 装饰器模式&#xff0c;就是可以对一个对象无限装饰一些东西&#xff0c;而且可以没有顺序。比如一个人可能只会说出他的名字&#xff0c;但是可以让他再说哈哈&#xff0c;可以说完哈哈之后再说哇哇。如何后面又不想装饰了&#xff0c;不需要改类原来的代码&#xff0c;…

基于深度学习的人脸性别年龄识别 - 图像识别 opencv 计算机竞赛

文章目录 0 前言1 课题描述2 实现效果3 算法实现原理3.1 数据集3.2 深度学习识别算法3.3 特征提取主干网络3.4 总体实现流程 4 具体实现4.1 预训练数据格式4.2 部分实现代码 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 毕业设计…

智慧校园地下管线三维可视化管控平台减少人力和物力资源的浪费

随着科技的不断发展&#xff0c;三维可视化管理平台在各个领域得到了广泛的应用。三维可视化管理平台通过将数据以三维形式呈现&#xff0c;使得用户能够更直观地理解和分析数据&#xff0c;从而提高工作效率和决策质量。 VR数字孪生园区系统是通过将实际园区的各种数据和信息进…

RabbitMQ入门到实战教程,消息队列实战,改造配置MQ

RabbitMQ入门到实战教程&#xff0c;MQ消息中间件&#xff0c;消息队列实战-CSDN博客 3.7.Topic交换机 3.7.1.说明 Topic类型的Exchange与Direct相比&#xff0c;都是可以根据RoutingKey把消息路由到不同的队列。 只不过Topic类型Exchange可以让队列在绑定BindingKey 的时候…

C语言实现获取文件大小、创建时间、修改时间(stat结构体)

源代码&#xff1a; #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <sys/stat.h> #include <sys/types.h>#define EXE_ABORT() {system("pause");return 0;} #define FILEPATH &q…

如何优雅地单元测试 Kotlin/Java 中的 private 方法?

翻译自 https://medium.com/mindorks/how-to-unit-test-private-methods-in-java-and-kotlin-d3cae49dccd ❓如何单元测试 Kotlin/Java 中的 private 方法❓ 首先&#xff0c;开发者应该测试代码里的 private 私有方法吗&#xff1f; 直接信任这些私有方法&#xff0c;测试到…

系列四、全局配置mybatis-config.xml

一、全局配置文件中的属性 mybatis全局配置中的文件非常多&#xff0c;主要有如下几个&#xff1a; properties&#xff08;属性&#xff09;settings&#xff08;全局配置参数&#xff09;typeAliases&#xff08;类型别名&#xff09;typeHandlers&#xff08;类型处理器&am…