ABP_VNext 动态Api客户端访问坑
动态API客户端访问过程由于API描述的名称不一致导致的坑,通过查询资料学习记录如下:
1、通过AOP拦截器实现远端接口代理访问实现
访问远端接口当然还是通过HttpClient直接访问了,大致访问过程如下:
- 获取入口处配置的,服务接口类型和服务地址标记KEY
- 根据服务地址标记KEY获取服务地址信息,主要是HOST地址,API版本
- 获取远端服务的接口描述
- 根据接口描述,构造请求路径,序列化参数、添加认证信息,发送请求
- 根据接口描述,获取请求结果,进行反序列化
实现类使用ABP的动态拦截实现如下: public class DynamicHttpProxyInterceptor : AbpInterceptor, ITransientDependency;主要实现方法在MakeRequestAsync里面,使用
HttpClientFactory构造HttpClient来请求,本次访问坑在于使用
RequestPayloadBuilder构建请求时使用HttpActionParameterHelper来获取匹配参数变量,由于对
ParameterApiDescriptionModel不是很了解,导致了名称错配的坑,这里一个重点就是如何能知道对方的服务接口描述信息?我们定义了一个C#接口,这个接口是如何被客户端获取描述信息的呢?我们分析代码得到在调用过程中使用ApiDescriptionFinder.FindActionAsync进行API描述的信息的查找。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public static object FindParameterValue(IReadOnlyDictionary< string , object > methodArguments, ParameterApiDescriptionModel apiParameter) { var value = methodArguments.GetOrDefault(apiParameter.NameOnMethod); if (value == null ) { return null ; } if (apiParameter.Name == apiParameter.NameOnMethod) { return value; } return ReflectionHelper.GetValueByPath(value, value.GetType(), apiParameter.Name); } |
2、如何查找远端API描述信息
ApiDescriptionFinder.FindActionAsync看到其内部通过调用对方服务站点下的/api/abp/api-definition接口来获取的接口描述,远程接口提供方还提供一个api/abp/api-definition的接口,根据我们本地的接口定义信息能够找到远程接口描述,具体这个API元数据接口代码如下:
// 查找API描述信息 ApiDescriptionFinder.FindActionAsync(remoteServiceConfig.BaseUrl, typeof(TService), invocation.Method) // 内部又会调用如下接口,调用远程服务站点下的接口 protected virtual async Task<ApplicationApiDescriptionModel> GetApiDescriptionFromServerAsync(string baseUrl) { using (var client = HttpClientFactory.Create()) { // ABP VNext默认的实现,调用一个固定的地址,如果对方不是采用Abp框架来提供接口,只能模拟适配这个接口的返回了 var response = await client.GetAsync( baseUrl.EnsureEndsWith('/') + "api/abp/api-definition", CancellationTokenProvider.Token ).ConfigureAwait(false); // ... } }
我们使用Abp框架进行开发,自带了这个接口,通过获取控制器Action的元数据信息,循环获取所有的API接口描述都返回,ABP的实现代码:
[Route("api/abp/api-definition")] public class AbpApiDefinitionController : AbpController, IRemoteService { private readonly IApiDescriptionModelProvider _modelProvider; public AbpApiDefinitionController(IApiDescriptionModelProvider modelProvider) { _modelProvider = modelProvider; } [HttpGet] public ApplicationApiDescriptionModel Get() { return _modelProvider.CreateApiModel(); } } public class AspNetCoreApiDescriptionModelProvider : IApiDescriptionModelProvider, ITransientDependency { public ILogger<AspNetCoreApiDescriptionModelProvider> Logger { get; set; } private readonly IApiDescriptionGroupCollectionProvider _descriptionProvider; private readonly AbpAspNetCoreMvcOptions _options; private readonly AbpApiDescriptionModelOptions _modelOptions; public AspNetCoreApiDescriptionModelProvider( IApiDescriptionGroupCollectionProvider descriptionProvider, IOptions<AbpAspNetCoreMvcOptions> options, IOptions<AbpApiDescriptionModelOptions> modelOptions) { _descriptionProvider = descriptionProvider; _options = options.Value; _modelOptions = modelOptions.Value; Logger = NullLogger<AspNetCoreApiDescriptionModelProvider>.Instance; } public ApplicationApiDescriptionModel CreateApiModel() { var model = ApplicationApiDescriptionModel.Create(); // 从 Microsoft.AspNetCore.Mvc.ApiExplorer.IApiDescriptionGroupCollectionProvider中获取描述信息 foreach (var descriptionGroupItem in _descriptionProvider.ApiDescriptionGroups.Items) { foreach (var apiDescription in descriptionGroupItem.Items) { if (!apiDescription.ActionDescriptor.IsControllerAction()) { continue; } AddApiDescriptionToModel(apiDescription, model); } } return model; } // ... }
对于其他语言开发的动态接口代理伪造请求参数的构造RequestPayloadBuilder,未有替换服务,是一种遗憾,通过查看最新的5.0,依然未开放。
另外:对于动态客户端使用的认证服务是由Abp的认证模块Volo.Abp.IdentityModel提供的,是通过IdentityModelAuthenticationService,其内部适配OIDC的客户端认证和密码两种模来提供接口认证,如果对方的接口认证不是OIDC实现的两种规范,则需要去重写这个认证服务,我们服务未采用IdentityServer4,所以使用客户端替换服务,替换掉这个服务IRemoteServiceHttpClientAuthenticator;
if (requestContext.Action.AllowAnonymous != true) { await ClientAuthenticator.Authenticate( new RemoteServiceHttpClientAuthenticateContext( client, requestMessage, remoteServiceConfig, clientConfig.RemoteServiceName ) ); }
参考:
1、动态API客户端文档: https://docs.abp.io/zh-Hans/abp/latest/AspNetCore/Dynamic-CSharp-API-Client
2、dotnet_core_learning:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)