using NCC.DataValidation;
using NCC.Dependency;
using NCC.Extensions;
using NCC.Reflection;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace NCC.RemoteRequest
{
///
/// 远程请求实现类(以下代码还需进一步优化性能,启动时把所有扫描缓存起来)
///
[SuppressSniffer]
public class HttpDispatchProxy : AspectDispatchProxy, IDispatchProxy
{
///
/// 被代理对象
///
public object Target { get; set; }
///
/// 服务提供器
///
public IServiceProvider Services { get; set; }
///
/// 拦截同步方法
///
///
///
///
public override object Invoke(MethodInfo method, object[] args)
{
throw new NotSupportedException("Please use asynchronous operation mode.");
}
///
/// 拦截异步无返回方法
///
///
///
///
public async override Task InvokeAsync(MethodInfo method, object[] args)
{
var httpRequestPart = BuildHttpRequestPart(method, args);
_ = await httpRequestPart.SendAsync();
}
///
/// 拦截异步带返回方法
///
///
///
///
///
public override Task InvokeAsyncT(MethodInfo method, object[] args)
{
var httpRequestPart = BuildHttpRequestPart(method, args);
var result = httpRequestPart.SendAsAsync();
return result;
}
///
/// 构建 HttpClient 请求部件
///
///
///
///
private HttpRequestPart BuildHttpRequestPart(MethodInfo method, object[] args)
{
// 判断方法是否是远程代理请求方法
if (!method.IsDefined(typeof(HttpMethodBaseAttribute), true)) throw new InvalidOperationException($"{method.Name} is not a valid request proxy method.");
// 解析方法参数及参数值
var parameters = method.GetParameters().Select((u, i) => new MethodParameterInfo
{
Parameter = u,
Name = u.Name,
Value = args[i]
});
// 获取请求配置
var httpMethodBase = method.GetCustomAttribute(true);
// 创建请求配置对象
var httpRequestPart = new HttpRequestPart();
httpRequestPart.SetRequestUrl(httpMethodBase.RequestUrl)
.SetHttpMethod(httpMethodBase.Method)
.SetTemplates(parameters.ToDictionary(u => u.Name, u => u.Value))
.SetRequestScoped(Services);
// 设置请求客户端
var clientAttribute = method.GetFoundAttribute(true);
if (clientAttribute != null) httpRequestPart.SetClient(clientAttribute.Name);
// 设置请求超时时间
var timeout = method.GetFoundAttribute(true)?.Seconds;
if (timeout != null && timeout.Value > 0) httpRequestPart.SetClientTimeout(timeout.Value);
// 设置请求报文头
SetHeaders(method, parameters, httpRequestPart);
// 设置 Url 地址参数
SetQueries(parameters, httpRequestPart);
// 设置 Body 信息
SetBody(parameters, httpRequestPart);
// 设置验证
SetValidation(parameters);
// 设置序列化提供器
SetJsonSerialization(method, parameters, httpRequestPart);
// 配置全局拦截
CallGlobalInterceptors(httpRequestPart, method.DeclaringType);
// 设置请求拦截
SetInterceptors(parameters, httpRequestPart);
// 设置重试
var retryPolicyAttribute = method.GetFoundAttribute(true);
if (retryPolicyAttribute != null) httpRequestPart.SetRetryPolicy(retryPolicyAttribute.NumRetries, retryPolicyAttribute.RetryTimeout);
return httpRequestPart;
}
///
/// 设置 Url 地址参数
///
///
///
private static void SetQueries(IEnumerable parameters, HttpRequestPart httpRequestPart)
{
// 配置 Url 地址参数
var queryParameters = parameters.Where(u => u.Parameter.IsDefined(typeof(QueryStringAttribute), true));
var parameterQueries = new Dictionary();
foreach (var item in queryParameters)
{
var queryStringAttribute = item.Parameter.GetCustomAttribute();
if (item.Value != null) parameterQueries.Add(queryStringAttribute.Alias ?? item.Name, item.Value);
}
httpRequestPart.SetQueries(parameterQueries);
}
///
/// 设置 Body 参数
///
///
///
private static void SetBody(IEnumerable parameters, HttpRequestPart httpRequestPart)
{
// 配置 Body 参数,只取第一个
var bodyParameter = parameters.FirstOrDefault(u => u.Parameter.IsDefined(typeof(BodyAttribute), true));
if (bodyParameter != null)
{
var bodyAttribute = bodyParameter.Parameter.GetCustomAttribute(true);
httpRequestPart.SetBody(bodyParameter.Value, bodyAttribute.ContentType, Encoding.GetEncoding(bodyAttribute.Encoding));
}
// 查找所有贴了 [BodyBytes] 特性的参数
var bodyBytesParameters = parameters.Where(u => u.Parameter.IsDefined(typeof(BodyBytesAttribute), true));
if (bodyBytesParameters != null)
{
var bodyBytes = new List<(string Name, byte[] Bytes, string FileName)>();
foreach (var item in bodyBytesParameters)
{
var bodyBytesAttribute = item.Parameter.GetCustomAttribute();
if (item.Value != null && item.Value.GetType() == typeof(byte[])) bodyBytes.Add((bodyBytesAttribute.Alias ?? item.Name, (byte[])item.Value, bodyBytesAttribute.FileName));
}
httpRequestPart.SetBodyBytes(bodyBytes.ToArray());
}
}
///
/// 设置验证
///
///
private static void SetValidation(IEnumerable parameters)
{
// 验证参数,查询所有配置验证特性的参数,排除 Body 验证
var validateParameters = parameters.Where(u => u.Parameter.IsDefined(typeof(ValidationAttribute), true) && !u.Parameter.IsDefined(typeof(BodyAttribute), true));
foreach (var item in validateParameters)
{
// 处理空值
var isRequired = item.Parameter.IsDefined(typeof(RequiredAttribute), true);
if (isRequired && item.Value == null) throw new InvalidOperationException($"{item.Name} can not be null.");
// 判断是否是基元类型
if (item.Parameter.ParameterType.IsRichPrimitive())
{
var validationAttributes = item.Parameter.GetCustomAttributes(true);
item.Value?.Validate(validationAttributes.ToArray());
}
else item.Value?.Validate();
}
}
///
/// 设置序列化
///
///
///
///
private static void SetJsonSerialization(MethodInfo method, IEnumerable parameters, HttpRequestPart httpRequestPart)
{
// 判断方法是否自定义序列化选项
var jsonSerializerOptions = parameters.FirstOrDefault(u => u.Parameter.IsDefined(typeof(JsonSerializerOptionsAttribute), true))?.Value
// 获取静态方法且贴有 [JsonSerializerOptions] 特性的缺省配置
?? method.DeclaringType.GetMethods()
.FirstOrDefault(u => u.IsDefined(typeof(JsonSerializerOptionsAttribute), true))
?.Invoke(null, null);
// 查询自定义序列化提供器,如果没找到,默认 SystemTextJsonSerializerProvider
var jsonSerializerProvider = method.GetFoundAttribute(true)?.ProviderType;
httpRequestPart.SetJsonSerialization(jsonSerializerProvider, jsonSerializerOptions);
}
///
/// 调用全局拦截
///
///
///
private static void CallGlobalInterceptors(HttpRequestPart httpRequestPart, Type declaringType)
{
// 获取所有静态方法且贴有 [Interceptor] 特性
var interceptorMethods = declaringType.GetMethods()
.Where(u => u.IsDefined(typeof(InterceptorAttribute), true));
foreach (var method in interceptorMethods)
{
// 获取拦截器类型
var interceptor = method.GetCustomAttributes().First();
switch (interceptor.Type)
{
// 加载请求拦截
case InterceptorTypes.Request:
var onRequesting = (Action)Delegate.CreateDelegate(typeof(Action), method);
httpRequestPart.OnRequesting(onRequesting);
break;
// 加载响应拦截
case InterceptorTypes.Response:
var onResponsing = (Action)Delegate.CreateDelegate(typeof(Action), method);
httpRequestPart.OnResponsing(onResponsing);
break;
// 加载 Client 配置拦截
case InterceptorTypes.Client:
var onClientCreating = (Action)Delegate.CreateDelegate(typeof(Action), method);
httpRequestPart.OnClientCreating(onClientCreating);
break;
// 加载异常拦截
case InterceptorTypes.Exception:
var onException = (Action)Delegate.CreateDelegate(typeof(Action), method);
httpRequestPart.OnException(onException);
break;
default: break;
}
}
}
///
/// 设置请求拦截
///
///
///
private static void SetInterceptors(IEnumerable parameters, HttpRequestPart httpRequestPart)
{
// 添加方法拦截器
var Interceptors = parameters.Where(u => u.Parameter.IsDefined(typeof(InterceptorAttribute), true));
foreach (var item in Interceptors)
{
// 获取拦截器类型
var interceptor = item.Parameter.GetCustomAttribute();
switch (interceptor.Type)
{
// 加载请求拦截
case InterceptorTypes.Request:
if (item.Value is Action onRequesting)
{
httpRequestPart.OnRequesting(onRequesting);
}
break;
// 加载响应拦截
case InterceptorTypes.Response:
if (item.Value is Action onResponsing)
{
httpRequestPart.OnResponsing(onResponsing);
}
break;
// 加载 Client 配置拦截
case InterceptorTypes.Client:
if (item.Value is Action onClientCreating)
{
httpRequestPart.OnClientCreating(onClientCreating);
}
break;
// 加载异常拦截
case InterceptorTypes.Exception:
if (item.Value is Action onException)
{
httpRequestPart.OnException(onException);
}
break;
default: break;
}
}
}
///
/// 设置请求报文头
///
///
///
///
private static void SetHeaders(MethodInfo method, IEnumerable parameters, HttpRequestPart httpRequestPart)
{
var declaringType = method.DeclaringType;
// 获取声明类请求报文头
var declaringTypeHeaders = (declaringType.IsDefined(typeof(HeadersAttribute), true)
? declaringType.GetCustomAttributes(true)
: Array.Empty()).ToDictionary(u => u.Key, u => u.Value);
// 获取方法请求报文头
var methodHeaders = (method.IsDefined(typeof(HeadersAttribute), true)
? method.GetCustomAttributes(true)
: Array.Empty()).ToDictionary(u => u.Key, u => u.Value);
// 获取参数请求报文头
var headerParameters = parameters.Where(u => u.Parameter.IsDefined(typeof(HeadersAttribute), true));
var parameterHeaders = new Dictionary();
foreach (var item in headerParameters)
{
var headersAttribute = item.Parameter.GetCustomAttribute(true);
if (item.Value != null) parameterHeaders.Add(headersAttribute.Key ?? item.Name, item.Value);
}
// 合并所有请求报文头
var headers = declaringTypeHeaders.AddOrUpdate(methodHeaders)
.AddOrUpdate(parameterHeaders);
httpRequestPart.SetHeaders(headers);
}
}
}