前言

当前.NET环境下,生成WebApi代理类的工具已经有很多选择了,比如OpenApi Generator,NSwagRefitter等,不同的工具生成的代码风格以及实现方式略有不同,比如Refitter生成的客户端是Refit风格.

本人比较喜欢Refit风格的标注风格因此还是比较喜欢使用Refitter的,TA生成的代码风格如下:

[Headers("Accept: application/json")]
[Get("/pet/{petId}")]
Task<Pet> GetPetById(long petId);

不过呢今天介绍的主角是Kiota,这个MS于2023年正式发布的一款代理生成工具,体验还是挺棒的,毫不夸张的说,算是这一领域的新贵了!

Kiota有以下诸多特性:

  • 支持多种语言:C#、CLI、Go、Java、PHP、Python、Ruby、Swift 和 TypeScript
  • 使用 OpenAPI 描述的全部功能
  • 能够轻松实施新的语言支持
  • 通过在核心库上构建,仅生成必要的源代码
  • 最小化外部依赖性
  • 使用 JSON Schema 描述生成基于基元的模型序列化/反序列化代码
  • 仅允许为OpenAPI描述的指定子集生成代码
  • 生成使 IDE 能够自动完成以帮助发现 API 资源的代码
  • 启用对 HTTP 功能的完全访问

命令行工具安装

接下来我们简单使用一下该工具:

当前以我们使用最多的Windows操作系统为例,首先安装NET8SDK,然后打开命令行工具,安装Kiota,当前最新版已经更新到了 1.17.0:

dotnet tool install --global Microsoft.OpenApi.Kiota

命令行生成代理

接下来我们随意创建一个NET8的MinimalApi项目,然后我们以Petshop3的Api为例,为了加快速度我们将接口Scheme文件下载到项目文件夹下:

文档地址为: https://petstore3.swagger.io/api/v3/openapi.json

当然了你也可以使用自己的WebApi;Schema文件下载完成后 我们使用命令行工具定位到对应的文件夹,然后键入如下命令:

kiota generate -l CSharp -o output -d petstore.json -n PetShops.V3

这里解释一下参数:

  • -l是客户端目标语言,CSharp就是C#
  • -o表示生成的代理类文件保存的文件夹
  • -d表示对应的schema文件,
  • -n表示生成的代理类的命名空间

    当然还有一些其他的参数这里就不一一列举,比如按需生成(排除保留指定的Api),有兴趣可以查看官方文档

如果没有其他问题,将会成功创建代理文件:

生成了代理类那使用起来就相当简单了:

调用生成的代理

接下来我们引用Kiota必须的几个类库:

<PackageReference Include="Microsoft.Kiota.Abstractions" />
<PackageReference Include="Microsoft.Kiota.Http.HttpClientLibrary" />
<PackageReference Include="Microsoft.Kiota.Serialization.Form" />
<PackageReference Include="Microsoft.Kiota.Serialization.Json"/>
<PackageReference Include="Microsoft.Kiota.Serialization.Multipart" />
<PackageReference Include="Microsoft.Kiota.Serialization.Text" />

这里假设PetShop的接口需要简单验证才能访问:

我们首先定义一个名为SimpleAuthenticationProvider的类,该类实现了IAuthenticationProvider接口,代码如下:


internal class SimpleAuthenticationProvider(string baseUrl, string? userName, string? password) : IAuthenticationProvider
{
public async Task AuthenticateRequestAsync(
RequestInformation request,
Dictionary<string, object>? additionalAuthenticationContext = null,
CancellationToken cancellationToken = default)
{
using var httpClient = new HttpClient()
{
BaseAddress = new Uri(baseUrl)
};
httpClient.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/xml"));
var authRequest = await httpClient.GetAsync(
$"v3/user/login?username={userName}&password={password}", cancellationToken); if (!authRequest.IsSuccessStatusCode)
{
throw new Exception("Authentication failed");
}
var session = await authRequest.Content.ReadAsStringAsync(cancellationToken); Console.WriteLine($"session: {session}");
await Task.CompletedTask;
//todo:
}
}

上面的代码很简单就是模拟一个登录,然后后面的请求就存在了session即可进行后续的接口调用,如果有些认证是JWT之内的这里可以把得到的Token传入到后续的Header中,当然认证请求务必缓存起来,不用每个接口调用都请求一次!

MS默认帮我们实现了AnonymousAuthenticationProviderBaseBearerTokenAuthenticationProvider两个认证Provider.

以下是简单的调用接口:

//分别调用条件查询Pet,以及根据Id查询指定的Pet
app.MapGet("/test", async () =>
{
var baseUrl = "https://petstore3.swagger.io/api/v3";
var userName = "万雅虎";
var password = "12345"; var adaptor = new HttpClientRequestAdapter(
new SimpleAuthenticationProvider(baseUrl, userName, password))
{
BaseUrl = baseUrl
};
var api = new ApiClient(adaptor);
var pets = await api.Pet.FindByStatus.GetAsync(x =>
{
x.QueryParameters.StatusAsGetStatusQueryParameterType =
PetShops.V3.Pet.FindByStatus.GetStatusQueryParameterType.Sold;
}); var pet = await api.Pet[1].GetAsync();
return new { Pets = pets, Pet = pet };
});

不出意外请求成功了:

注入ApiClient

当然上面的调用代码显得有一些粗糙,实际上大多数开发代码会使用到DI,

我们使用MS提供的示例代码扩展一下IServiceCollection

using Microsoft.Kiota.Http.HttpClientLibrary;

/// <summary>
/// Service collection extensions for Kiota handlers.
/// </summary>
public static class KiotaServiceCollectionExtensions
{
/// <summary>
/// Adds the Kiota handlers to the service collection.
/// </summary>
/// <param name="services"><see cref="IServiceCollection"/> to add the services to</param>
/// <returns><see cref="IServiceCollection"/> as per convention</returns>
/// <remarks>The handlers are added to the http client by the <see cref="AttachKiotaHandlers(IHttpClientBuilder)"/> call, which requires them to be pre-registered in DI</remarks>
public static IServiceCollection AddKiotaHandlers(this IServiceCollection services)
{
// Dynamically load the Kiota handlers from the Client Factory
var kiotaHandlers = KiotaClientFactory.GetDefaultHandlerTypes();
// And register them in the DI container
foreach(var handler in kiotaHandlers)
{
services.AddTransient(handler);
} return services;
} /// <summary>
/// Adds the Kiota handlers to the http client builder.
/// </summary>
/// <param name="builder"></param>
/// <returns></returns>
/// <remarks>
/// Requires the handlers to be registered in DI by <see cref="AddKiotaHandlers(IServiceCollection)"/>.
/// The order in which the handlers are added is important, as it defines the order in which they will be executed.
/// </remarks>
public static IHttpClientBuilder AttachKiotaHandlers(this IHttpClientBuilder builder)
{
// Dynamically load the Kiota handlers from the Client Factory
var kiotaHandlers = KiotaClientFactory.GetDefaultHandlerTypes();
// And attach them to the http client builder
foreach(var handler in kiotaHandlers)
{
builder.AddHttpMessageHandler((sp) => (DelegatingHandler)sp.GetRequiredService(handler));
}
return builder;
}
}

然后实现一个Api的ClientFactory:

//这里是伪代码,因为认证需要根据Api按需实现,比如这里是匿名请求
public class PetShopClientFactory
{
private readonly IAuthenticationProvider _authenticationProvider;
private readonly HttpClient _httpClient; public PetShopClientFactory(HttpClient httpClient)
{
_authenticationProvider = new AnonymousAuthenticationProvider();
_httpClient = httpClient;
} public ApiClient GetClient() {
return new ApiClient(new HttpClientRequestAdapter(_authenticationProvider, httpClient: _httpClient));
}
}

然后在服务注册中添加如下代码:


// ----------- Add this part to register the generated client -----------
// Add Kiota handlers to the dependency injection container
builder.Services.AddKiotaHandlers(); // Register the factory for the GitHub client
builder.Services.AddHttpClient<PetShopClientFactory>((sp, client) => {
// Set the base address and accept header
// or other settings on the http client
client.BaseAddress = new Uri("https://petstore3.swagger.io/api/v3");
client.DefaultRequestHeaders.Add("Accept", "application/json");
}).AttachKiotaHandlers(); // Attach the Kiota handlers to the http client, this is to enable all the Kiota features. // Register the GitHub client
builder.Services.AddTransient(sp => sp.GetRequiredService<PetShopClientFactory>().GetClient());
// ----------- Add this part to register the generated client end -------

最后我们在使用的地方注入ApiClient即可!

总结

对于不同的代理类和工具选型这里不做推荐,能满足项目需求以及节省开发时间即可,不过如果你有兴趣倒是推荐体验一下KiotaRefitter,没准你会和我一样喜欢上TA!

使用Kiota工具生成WebApi的代理类,以及接口调用的简单体验的更多相关文章

  1. 终于解决:升级至.NET 4.6.1后VS2015生成WCF客户端代理类的问题

    在Visual Studio 2015中将一个包含WCF引用的项目的targetFramework从4.5改为4.6.1的时候,VS2015会重新生成WCF客户端代理类.如果WCF引用配置中选中了&q ...

  2. WCF服务引用之后自动生成的泛型代理类名称太长的解决方案

    问题:WCF服务引用之后会将原来的泛型类自动生成一个代理类,但是有时候名称太长怎么办? 解决方案: 1.方案一: 调用客户端同样也引用这个泛型类的类库. 2.方案二: 找到这个泛型类,然后在上面的[D ...

  3. WCF透明代理类,动态调用,支持async/await

    我们希望WCF客户端调用采用透明代理方式,不用添加服务引用,也不用Invoke的方式,通过ChannelFactory<>动态产生通道,实现服务接口进行调用,并且支持async/await ...

  4. SpringBoot 动态代理实现三方接口调用

    目录 一.定义注解 二.建立动态代理类 三.注入spring容器 四.编写拦截器 五.创建客户端调用类 六.main方法测试 七.启动项目 在某些业务场景中,我们只需要业务代码中定义相应的接口或者相应 ...

  5. spring查看生成的cglib代理类源码详解

    1.让程序阻塞(抛出异常会导致程序结束,所以在抛出异常之前阻塞) 2. windows控制台 cd到jdk目录下的lib目录,找到sa-jdi.jar 执行: java -classpath sa-j ...

  6. 重学 Java 设计模式:实战代理模式「模拟mybatis-spring中定义DAO接口,使用代理类方式操作数据库原理实现场景」

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 难以跨越的瓶颈期,把你拿捏滴死死的! 编程开发学习过程中遇到的瓶颈期,往往是由于看不 ...

  7. Web Serveice服务代理类生成及编译

    本文链接地址:http://www.cnblogs.com/dengxinglin/p/3334158.html 一.生成代理类 对于web service服务和wcf的webservice服务,我们 ...

  8. 关于IIS寄宿WCF服务,客户端不能生成代理类

    我在使用VS2010写好WCF的Web服务后,部署在IIS7.0上,可以在IE9上进行访问,并且能显示XML数据,如下图 然后我在项目的客户端进行服务的添加引用,如下图 VS2010自动生成代理类,但 ...

  9. 探索Mybatis之JDK动态代理:探究Proxy.newProxyInstance()生成的代理类解析

    Mybatis的Mapper接口UserMapper 1 package com.safin.Mapper; 2 3 import com.safin.Pojo.User; 4 5 import ja ...

  10. Alibaba Java诊断工具Arthas查看Dubbo动态代理类

    原创/朱季谦 阅读Dubbo源码过程中,会发现,Dubbo消费端在做远程调用时,默认通过 Javassist 框架为服务接口生成动态代理类,接着再去调用代理类实现远程接口调用.在阅读这部分源码时,最后 ...

随机推荐

  1. Linux 内核:RCU机制与使用

    Linux 内核:RCU机制与使用 背景 学习Linux源码的时候,发现很多熟悉的数据结构多了__rcu后缀,因此了解了一下这些内容. 介绍 RCU(Read-Copy Update)是数据同步的一种 ...

  2. 全国产!全志T3+Logos FPGA开发板(4核ARM Cortex-A7)规格书

    评估板简介 创龙科技TLT3F-EVM是一款基于全志科技T3四核ARM Cortex-A7 + 紫光同创Logos PGL25G/PGL50G FPGA设计的异构多核国产工业评估板,ARM Corte ...

  3. 把nodejs程序打包成可执行文件

    在写好之后的nodejs程序,想发给同事的电脑上运行程序,就不得不下载node环境,还要安装第三方依赖包,非常的麻烦. 因此,可以借助一些插件来完成nodejs程序的打包,变成可以执行的文件. 将No ...

  4. 数学工具 | 如何将图片公式快速输入到Word中?

    背景: 在日常科研.学习与工作中,我们可能需要使用到某些书籍.期刊或者规范上的公式,但是如果自己纯手打则会相当麻烦(数学系LaTeX高手请忽略),因此如果有工具能够解决这个问题,那真的是解决了一大痛点 ...

  5. [oeasy]python0132_[趣味拓展]emoji_表情符号_抽象话_由来_流汗黄豆

    emoji表情符号 回忆上次内容 上次了解了unicode 和 utf-8 unicode是字符集 utf-8是一种可变长度的编码方式 utf-8是实现unicode的存储和传输的现实的方式   ​ ...

  6. oeasy教您玩转vim - 1 - # 存活下来 🥊

    存活下来 更新 apt 源,升级 vim vim 是什么 vim 是类 unix 系统上的一个文本编辑神器,在 Linux 系统环境中也被许多程序员使用,书写程序和文档. 我们本次课程将围绕 Vim ...

  7. 题解:AT_abc359_e [ABC359E] Water Tank

    背景 中考结束了,但是暑假只有一天,这就是我现在能在机房里面写题解的原因-- 分析 这道题就是个单调栈. 题目上问你第一滴水流到每个位置的时间.我们考虑,答案其实就是比当前木板高且距离当前木板最近的那 ...

  8. C# Win10缩放导致Winform字体模糊的解决方法

    问题描述 现在的笔记本电脑分辨率很高,基本上能达到1920*1080以上,因为笔记本的屏幕小,在这样的分辨率下一切看着都很小,尤其是文字,根本看不清,所以Win10很人性化的提供了屏幕缩放功能,一般默 ...

  9. pytest-req插件:更简单的做接口测试

    pytest-req插件:更简单的做接口测试 背景 我们经常会用到 pytest 和 requests 进行接口自动化测试. pytest 提供了非常方便的插件开发能力,在pytest中使用reque ...

  10. android常用布局基础学习

    总结:可水平放置可垂直放置也可穿插使用,默认为水平 <!--我在第一次使用权重的时候忽视了本线性布局中的宽度与高度,如果要使用权重,请将线性布局的最初大小设置为match_parent,否则不会 ...