Files
KinginfoGateway/src/Admin/ThingsGateway.Furion/V5_Experience/HttpRemote/Declarative/Builders/HttpDeclarativeBuilder.cs
2025-10-09 19:05:33 +08:00

152 lines
7.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ------------------------------------------------------------------------
// 版权信息
// 版权归百小僧及百签科技(广东)有限公司所有。
// 所有权利保留。
// 官方网站https://baiqian.com
//
// 许可证信息
// 项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// ------------------------------------------------------------------------
// ReSharper disable ArrangeObjectCreationWhenTypeNotEvident
using System.Collections.Concurrent;
using System.Reflection;
using ThingsGateway.Extension;
namespace ThingsGateway.HttpRemote;
/// <summary>
/// HTTP 声明式远程请求构建器
/// </summary>
/// <remarks>使用 <c>HttpRequestBuilder.Declarative(method, args)</c> 静态方法创建。</remarks>
public sealed class HttpDeclarativeBuilder
{
/// <summary>
/// HTTP 声明式 <see cref="IHttpDeclarativeExtractor" /> 提取器集合
/// </summary>
internal static readonly ConcurrentDictionary<Type, IHttpDeclarativeExtractor> _extractors = new([
new(typeof(BaseAddressDeclarativeExtractor), new BaseAddressDeclarativeExtractor()),
new(typeof(ValidationDeclarativeExtractor), new ValidationDeclarativeExtractor()),
new(typeof(AutoSetHostHeaderDeclarativeExtractor), new AutoSetHostHeaderDeclarativeExtractor()),
new(typeof(PerformanceOptimizationDeclarativeExtractor), new PerformanceOptimizationDeclarativeExtractor()),
new(typeof(HttpClientNameDeclarativeExtractor), new HttpClientNameDeclarativeExtractor()),
new(typeof(TraceIdentifierDeclarativeExtractor), new TraceIdentifierDeclarativeExtractor()),
new(typeof(ProfilerDeclarativeExtractor), new ProfilerDeclarativeExtractor()),
new(typeof(SimulateBrowserDeclarativeExtractor), new SimulateBrowserDeclarativeExtractor()),
new(typeof(AcceptLanguageDeclarativeExtractor), new AcceptLanguageDeclarativeExtractor()),
new(typeof(DisableCacheDeclarativeExtractor), new DisableCacheDeclarativeExtractor()),
new(typeof(EnsureSuccessStatusCodeDeclarativeExtractor), new EnsureSuccessStatusCodeDeclarativeExtractor()),
new(typeof(TimeoutDeclarativeExtractor), new TimeoutDeclarativeExtractor()),
new(typeof(PathSegmentDeclarativeExtractor), new PathSegmentDeclarativeExtractor()),
new(typeof(QueryDeclarativeExtractor), new QueryDeclarativeExtractor()),
new(typeof(PathDeclarativeExtractor), new PathDeclarativeExtractor()),
new(typeof(CookieDeclarativeExtractor), new CookieDeclarativeExtractor()),
new(typeof(RefererDeclarativeExtractor), new RefererDeclarativeExtractor()),
new(typeof(HeaderDeclarativeExtractor), new HeaderDeclarativeExtractor()),
new(typeof(PropertyDeclarativeExtractor), new PropertyDeclarativeExtractor()),
new(typeof(HttpVersionDeclarativeExtractor), new HttpVersionDeclarativeExtractor()),
new(typeof(SuppressExceptionsDeclarativeExtractor), new SuppressExceptionsDeclarativeExtractor()),
new(typeof(BodyDeclarativeExtractor), new BodyDeclarativeExtractor())
]);
/// <summary>
/// HTTP 声明式 <see cref="IHttpDeclarativeExtractor" /> 提取器集合(冻结)
/// </summary>
/// <remarks>该集合用于确保某些 HTTP 声明式提取器始终位于最后。</remarks>
internal static readonly ConcurrentDictionary<Type, IFrozenHttpDeclarativeExtractor> _frozenExtractors = new([
new(typeof(MultipartDeclarativeExtractor), new MultipartDeclarativeExtractor()),
new(typeof(HttpMultipartFormDataBuilderDeclarativeExtractor),
new HttpMultipartFormDataBuilderDeclarativeExtractor()),
new(typeof(HttpRequestBuilderDeclarativeExtractor), new HttpRequestBuilderDeclarativeExtractor())
]);
/// <summary>
/// 标识是否已加载自定义 HTTP 声明式提取器
/// </summary>
internal bool _hasLoadedExtractors;
/// <summary>
/// <inheritdoc cref="HttpDeclarativeBuilder" />
/// </summary>
/// <param name="method">被调用方法</param>
/// <param name="args">被调用方法的参数值数组</param>
internal HttpDeclarativeBuilder(MethodInfo method, object?[] args)
{
// 空检查
ArgumentNullException.ThrowIfNull(method);
ArgumentNullException.ThrowIfNull(args);
Method = method;
Args = args;
}
/// <summary>
/// 被调用方法
/// </summary>
public MethodInfo Method { get; }
/// <summary>
/// 被调用方法的参数值数组
/// </summary>
public object?[] Args { get; }
/// <summary>
/// 构建 <see cref="HttpRequestBuilder" /> 实例
/// </summary>
/// <param name="httpRemoteOptions">
/// <see cref="HttpRemoteOptions" />
/// </param>
/// <returns>
/// <see cref="HttpRequestBuilder" />
/// </returns>
/// <exception cref="InvalidOperationException"></exception>
internal HttpRequestBuilder Build(HttpRemoteOptions httpRemoteOptions)
{
// 空检查
ArgumentNullException.ThrowIfNull(httpRemoteOptions);
// 检查被调用方法是否贴有 [HttpMethod] 特性
if (!Method.IsDefined(typeof(HttpMethodAttribute), true))
{
throw new InvalidOperationException(
$"No `[HttpMethod]` annotation was found in method `{Method.ToFriendlyString()}` of type `{Method.DeclaringType?.ToFriendlyString()}`.");
}
// 获取 HttpMethodAttribute 实例
var httpMethodAttribute = Method.GetCustomAttribute<HttpMethodAttribute>(true)!;
// 初始化 HttpRequestBuilder 实例并添加声明式方法签名
var httpRequestBuilder = HttpRequestBuilder
.Create(httpMethodAttribute.HttpMethod, httpMethodAttribute.RequestUri)
.WithProperty(Constants.DECLARATIVE_METHOD_KEY,
$"{Method.ToFriendlyString()} | {Method.DeclaringType.ToFriendlyString()}");
// 初始化 HttpDeclarativeExtractorContext 实例
var httpDeclarativeExtractorContext = new HttpDeclarativeExtractorContext(Method, Args);
// 检查是否已加载自定义 HTTP 声明式提取器
if (!_hasLoadedExtractors)
{
_hasLoadedExtractors = true;
// 添加自定义 IHttpDeclarativeExtractor 数组
_extractors.TryAdd(httpRemoteOptions.HttpDeclarativeExtractors?.SelectMany(u => u.Invoke()).ToArray(),
value => value.GetType());
}
// 组合所有 HTTP 声明式提取器
var extractors = _extractors.Values.Concat(_frozenExtractors.Values.OrderByDescending(e => e.Order)).ToArray();
// 遍历 HTTP 声明式提取器集合
foreach (var extractor in extractors)
{
// 提取方法信息构建 HttpRequestBuilder 实例
extractor.Extract(httpRequestBuilder, httpDeclarativeExtractorContext);
}
return httpRequestBuilder;
}
}