mirror of
https://gitee.com/ThingsGateway/ThingsGateway.git
synced 2025-10-20 10:50:48 +08:00
353 lines
13 KiB
C#
353 lines
13 KiB
C#
// ------------------------------------------------------------------------
|
||
// 版权信息
|
||
// 版权归百小僧及百签科技(广东)有限公司所有。
|
||
// 所有权利保留。
|
||
// 官方网站:https://baiqian.com
|
||
//
|
||
// 许可证信息
|
||
// 项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。
|
||
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
|
||
// ------------------------------------------------------------------------
|
||
|
||
using Microsoft.Extensions.DependencyInjection;
|
||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||
using Microsoft.Extensions.Logging;
|
||
|
||
using System.Reflection;
|
||
using System.Text;
|
||
|
||
using ThingsGateway.Extension;
|
||
|
||
namespace ThingsGateway.HttpRemote;
|
||
|
||
/// <summary>
|
||
/// HTTP 远程请求构建器
|
||
/// </summary>
|
||
public sealed class HttpRemoteBuilder
|
||
{
|
||
/// <summary>
|
||
/// <see cref="IHttpContentConverter" /> 集合
|
||
/// </summary>
|
||
internal IList<Func<IEnumerable<IHttpContentConverter>>>? _httpContentConverterProviders;
|
||
|
||
/// <summary>
|
||
/// <see cref="IHttpContentProcessor" /> 集合
|
||
/// </summary>
|
||
internal IList<Func<IEnumerable<IHttpContentProcessor>>>? _httpContentProcessorProviders;
|
||
|
||
/// <summary>
|
||
/// <see cref="IHttpDeclarativeExtractor" /> 集合
|
||
/// </summary>
|
||
internal IList<Func<IEnumerable<IHttpDeclarativeExtractor>>>? _httpDeclarativeExtractors;
|
||
|
||
/// <summary>
|
||
/// <see cref="IHttpDeclarative" /> 类型集合
|
||
/// </summary>
|
||
internal HashSet<Type>? _httpDeclarativeTypes;
|
||
|
||
/// <summary>
|
||
/// <see cref="IObjectContentConverterFactory" /> 实现类型
|
||
/// </summary>
|
||
internal Type? _objectContentConverterFactoryType;
|
||
|
||
/// <summary>
|
||
/// 添加 <see cref="IHttpContentProcessor" /> 请求内容处理器
|
||
/// </summary>
|
||
/// <remarks>支持多次调用。</remarks>
|
||
/// <param name="configure"><see cref="IHttpContentProcessor" /> 实例提供器</param>
|
||
/// <returns>
|
||
/// <see cref="HttpRemoteBuilder" />
|
||
/// </returns>
|
||
public HttpRemoteBuilder AddHttpContentProcessors(Func<IEnumerable<IHttpContentProcessor>> configure)
|
||
{
|
||
// 空检查
|
||
ArgumentNullException.ThrowIfNull(configure);
|
||
|
||
_httpContentProcessorProviders ??= new List<Func<IEnumerable<IHttpContentProcessor>>>();
|
||
|
||
_httpContentProcessorProviders.Add(configure);
|
||
|
||
return this;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加 <see cref="IHttpContentConverter" /> 响应内容转换器
|
||
/// </summary>
|
||
/// <remarks>支持多次调用。</remarks>
|
||
/// <param name="configure"><see cref="IHttpContentConverter" /> 实例提供器</param>
|
||
/// <returns>
|
||
/// <see cref="HttpRemoteBuilder" />
|
||
/// </returns>
|
||
public HttpRemoteBuilder AddHttpContentConverters(Func<IEnumerable<IHttpContentConverter>> configure)
|
||
{
|
||
// 空检查
|
||
ArgumentNullException.ThrowIfNull(configure);
|
||
|
||
_httpContentConverterProviders ??= new List<Func<IEnumerable<IHttpContentConverter>>>();
|
||
|
||
_httpContentConverterProviders.Add(configure);
|
||
|
||
return this;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置 <see cref="IObjectContentConverterFactory" /> 对象内容转换器工厂
|
||
/// </summary>
|
||
/// <typeparam name="TFactory">
|
||
/// <see cref="IObjectContentConverterFactory" />
|
||
/// </typeparam>
|
||
/// <returns>
|
||
/// <see cref="HttpRemoteBuilder" />
|
||
/// </returns>
|
||
public HttpRemoteBuilder UseObjectContentConverterFactory<TFactory>()
|
||
where TFactory : IObjectContentConverterFactory =>
|
||
UseObjectContentConverterFactory(typeof(TFactory));
|
||
|
||
/// <summary>
|
||
/// 设置 <see cref="IObjectContentConverterFactory" /> 对象内容转换器工厂
|
||
/// </summary>
|
||
/// <param name="factoryType">
|
||
/// <see cref="IObjectContentConverterFactory" />
|
||
/// </param>
|
||
/// <returns>
|
||
/// <see cref="HttpRemoteBuilder" />
|
||
/// </returns>
|
||
/// <exception cref="ArgumentException"></exception>
|
||
public HttpRemoteBuilder UseObjectContentConverterFactory(Type factoryType)
|
||
{
|
||
// 空检查
|
||
ArgumentNullException.ThrowIfNull(factoryType);
|
||
|
||
// 检查类型是否实现了 IObjectContentConverterFactory 接口
|
||
if (!typeof(IObjectContentConverterFactory).IsAssignableFrom(factoryType))
|
||
{
|
||
throw new ArgumentException(
|
||
$"`{factoryType}` type is not assignable from `{typeof(IObjectContentConverterFactory)}`.",
|
||
nameof(factoryType));
|
||
}
|
||
|
||
_objectContentConverterFactoryType = factoryType;
|
||
|
||
return this;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加 HTTP 声明式服务
|
||
/// </summary>
|
||
/// <typeparam name="TDeclarative">
|
||
/// <see cref="IHttpDeclarative" />
|
||
/// </typeparam>
|
||
/// <returns>
|
||
/// <see cref="HttpRemoteBuilder" />
|
||
/// </returns>
|
||
public HttpRemoteBuilder AddHttpDeclarative<TDeclarative>()
|
||
where TDeclarative : IHttpDeclarative =>
|
||
AddHttpDeclarative(typeof(TDeclarative));
|
||
|
||
/// <summary>
|
||
/// 添加 HTTP 声明式服务
|
||
/// </summary>
|
||
/// <param name="declarativeType">
|
||
/// <see cref="IHttpDeclarative" />
|
||
/// </param>
|
||
/// <returns>
|
||
/// <see cref="HttpRemoteBuilder" />
|
||
/// </returns>
|
||
/// <exception cref="ArgumentException"></exception>
|
||
public HttpRemoteBuilder AddHttpDeclarative(Type declarativeType)
|
||
{
|
||
// 空检查
|
||
ArgumentNullException.ThrowIfNull(declarativeType);
|
||
|
||
// 检查类型是否是接口且实现了 IHttpDeclarative 接口
|
||
if (!declarativeType.IsInterface || !typeof(IHttpDeclarative).IsAssignableFrom(declarativeType))
|
||
{
|
||
throw new ArgumentException(
|
||
$"`{declarativeType}` type is not assignable from `{typeof(IHttpDeclarative)}` or interface.",
|
||
nameof(declarativeType));
|
||
}
|
||
|
||
_httpDeclarativeTypes ??= [];
|
||
|
||
_httpDeclarativeTypes.Add(declarativeType);
|
||
|
||
return this;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加 HTTP 声明式服务
|
||
/// </summary>
|
||
/// <param name="declarativeTypes">
|
||
/// <see cref="IHttpDeclarative" /> 集合
|
||
/// </param>
|
||
/// <returns>
|
||
/// <see cref="HttpRemoteBuilder" />
|
||
/// </returns>
|
||
/// <exception cref="ArgumentException"></exception>
|
||
public HttpRemoteBuilder AddHttpDeclaratives(params IEnumerable<Type> declarativeTypes)
|
||
{
|
||
// 空检查
|
||
ArgumentNullException.ThrowIfNull(declarativeTypes);
|
||
|
||
foreach (var declarativeType in declarativeTypes)
|
||
{
|
||
AddHttpDeclarative(declarativeType);
|
||
}
|
||
|
||
return this;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 扫描程序集并添加 HTTP 声明式服务
|
||
/// </summary>
|
||
/// <param name="assemblies"><see cref="Assembly" /> 集合</param>
|
||
/// <returns>
|
||
/// <see cref="HttpRemoteBuilder" />
|
||
/// </returns>
|
||
public HttpRemoteBuilder AddHttpDeclarativeFromAssemblies(params IEnumerable<Assembly?> assemblies)
|
||
{
|
||
// 空检查
|
||
ArgumentNullException.ThrowIfNull(assemblies);
|
||
|
||
AddHttpDeclaratives(assemblies.SelectMany(ass =>
|
||
(ass?.GetExportedTypes() ?? Enumerable.Empty<Type>()).Where(t =>
|
||
t.IsInterface && typeof(IHttpDeclarative).IsAssignableFrom(t))));
|
||
|
||
return this;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加 HTTP 声明式 <see cref="IHttpDeclarativeExtractor" /> 提取器
|
||
/// </summary>
|
||
/// <remarks>支持多次调用。</remarks>
|
||
/// <param name="configure"><see cref="IHttpDeclarativeExtractor" /> 实例提供器</param>
|
||
/// <returns>
|
||
/// <see cref="HttpRemoteBuilder" />
|
||
/// </returns>
|
||
public HttpRemoteBuilder AddHttpDeclarativeExtractors(Func<IEnumerable<IHttpDeclarativeExtractor>> configure)
|
||
{
|
||
// 空检查
|
||
ArgumentNullException.ThrowIfNull(configure);
|
||
|
||
_httpDeclarativeExtractors ??= new List<Func<IEnumerable<IHttpDeclarativeExtractor>>>();
|
||
|
||
_httpDeclarativeExtractors.Add(configure);
|
||
|
||
return this;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 扫描程序集并添加 HTTP 声明式 <see cref="IHttpDeclarativeExtractor" /> 提取器
|
||
/// </summary>
|
||
/// <remarks>支持多次调用。</remarks>
|
||
/// <param name="assemblies"><see cref="Assembly" /> 集合</param>
|
||
/// <returns>
|
||
/// <see cref="HttpRemoteBuilder" />
|
||
/// </returns>
|
||
public HttpRemoteBuilder AddHttpDeclarativeExtractorFromAssemblies(params IEnumerable<Assembly?> assemblies)
|
||
{
|
||
// 空检查
|
||
ArgumentNullException.ThrowIfNull(assemblies);
|
||
|
||
return AddHttpDeclarativeExtractors(() => assemblies.SelectMany(ass =>
|
||
(ass?.GetExportedTypes() ?? Enumerable.Empty<Type>()).Where(t =>
|
||
t.HasDefinePublicParameterlessConstructor() && typeof(IHttpDeclarativeExtractor).IsAssignableFrom(t))
|
||
.Select(t => (IHttpDeclarativeExtractor)Activator.CreateInstance(t)!)));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建模块服务
|
||
/// </summary>
|
||
/// <param name="services">
|
||
/// <see cref="IServiceCollection" />
|
||
/// </param>
|
||
internal void Build(IServiceCollection services)
|
||
{
|
||
// 注册 CodePagesEncodingProvider,使得程序能够识别并使用 Windows 代码页中的各种编码
|
||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||
|
||
// 注册日志服务
|
||
services.AddLogging();
|
||
|
||
// 注册默认 HttpClient 客户端
|
||
if (services.All(u => u.ServiceType != typeof(IHttpClientFactory)))
|
||
{
|
||
services.AddHttpClient();
|
||
}
|
||
|
||
// 检查是否配置(注册)了日志程序
|
||
var isLoggingRegistered = services.Any(u => u.ServiceType == typeof(ILoggerProvider));
|
||
|
||
// 注册并配置 HttpRemoteOptions 选项服务
|
||
services.Configure<HttpRemoteOptions>(options =>
|
||
{
|
||
options.HttpDeclarativeExtractors = _httpDeclarativeExtractors?.AsReadOnly();
|
||
options.IsLoggingRegistered = isLoggingRegistered;
|
||
});
|
||
|
||
// 注册 HttpContent 内容处理器工厂
|
||
services.TryAddSingleton<IHttpContentProcessorFactory>(provider =>
|
||
new HttpContentProcessorFactory(provider,
|
||
_httpContentProcessorProviders?.SelectMany(u => u.Invoke()).ToArray()));
|
||
|
||
// 注册 HttpContent 内容转换器工厂
|
||
services.TryAddSingleton<IHttpContentConverterFactory>(provider =>
|
||
new HttpContentConverterFactory(provider,
|
||
_httpContentConverterProviders?.SelectMany(u => u.Invoke()).ToArray()));
|
||
|
||
// 注册对象内容转换器工厂
|
||
services.TryAddSingleton<IObjectContentConverterFactory, ObjectContentConverterFactory>();
|
||
|
||
// 注册 HTTP 远程请求服务
|
||
services.TryAddSingleton<IHttpRemoteService, HttpRemoteService>();
|
||
|
||
// 检查是否自定义了对象内容转换器工厂,如果存在则替换
|
||
if (_objectContentConverterFactoryType is not null &&
|
||
_objectContentConverterFactoryType != typeof(ObjectContentConverterFactory))
|
||
{
|
||
services.Replace(ServiceDescriptor.Singleton(typeof(IObjectContentConverterFactory),
|
||
_objectContentConverterFactoryType));
|
||
}
|
||
|
||
// 构建 HTTP 声明式远程请求服务
|
||
BuildHttpDeclarativeServices(services);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建 HTTP 声明式远程请求服务
|
||
/// </summary>
|
||
/// <param name="services">
|
||
/// <see cref="IServiceCollection" />
|
||
/// </param>
|
||
internal void BuildHttpDeclarativeServices(IServiceCollection services)
|
||
{
|
||
// 空检查
|
||
if (_httpDeclarativeTypes is null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 初始化 HTTP 声明式远程请求代理类类型
|
||
var httpDeclarativeDispatchProxyType = typeof(HttpDeclarativeDispatchProxy);
|
||
|
||
// 遍历 HTTP 声明式远程请求类型并注册为服务
|
||
foreach (var httpDeclarativeType in _httpDeclarativeTypes)
|
||
{
|
||
services.TryAddSingleton(httpDeclarativeType, provider =>
|
||
{
|
||
// 创建 HTTP 声明式远程请求代理实例
|
||
var httpDeclarative =
|
||
DispatchProxyAsync.Create(httpDeclarativeType, httpDeclarativeDispatchProxyType) as
|
||
HttpDeclarativeDispatchProxy;
|
||
|
||
// 空检查
|
||
ArgumentNullException.ThrowIfNull(httpDeclarative);
|
||
|
||
// 解析 IHttpRemoteService 服务并设置给 RemoteService 属性
|
||
httpDeclarative.RemoteService = provider.GetRequiredService<IHttpRemoteService>();
|
||
|
||
return httpDeclarative;
|
||
});
|
||
}
|
||
}
|
||
} |