using NCC.ClayObject.Extensions;
using NCC.DataValidation;
using NCC.FriendlyException;
using NCC.JsonSerialization;
using NCC.Templates.Extensions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
namespace NCC.RemoteRequest
{
///
/// HttpClient 对象组装部件
///
public sealed partial class HttpRequestPart
{
///
/// 请求失败事件
///
public event EventHandler OnRequestFailded;
///
/// MiniProfiler 分类名
///
private const string MiniProfilerCategory = "httpclient";
///
/// 发送 GET 请求返回 T 对象
///
///
///
///
public Task GetAsAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Get).SendAsAsync(cancellationToken);
}
///
/// 发送 GET 请求返回 Stream
///
///
///
public Task GetAsStreamAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Get).SendAsStreamAsync(cancellationToken);
}
///
/// 发送 GET 请求返回 String
///
///
///
public Task GetAsStringAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Get).SendAsStringAsync(cancellationToken);
}
///
/// 发送 GET 请求
///
///
///
public Task GetAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Get).SendAsync(cancellationToken);
}
///
/// 发送 POST 请求返回 T 对象
///
///
///
///
public Task PostAsAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Post).SendAsAsync(cancellationToken);
}
///
/// 发送 POST 请求返回 Stream
///
///
///
public Task PostAsStreamAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Post).SendAsStreamAsync(cancellationToken);
}
///
/// 发送 POST 请求返回 String
///
///
///
public Task PostAsStringAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Post).SendAsStringAsync(cancellationToken);
}
///
/// 发送 POST 请求
///
///
///
public Task PostAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Post).SendAsync(cancellationToken);
}
///
/// 发送 PUT 请求返回 T 对象
///
///
///
///
public Task PutAsAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Put).SendAsAsync(cancellationToken);
}
///
/// 发送 PUT 请求返回 Stream
///
///
///
public Task PutAsStreamAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Put).SendAsStreamAsync(cancellationToken);
}
///
/// 发送 PUT 请求返回 String
///
///
///
public Task PutAsStringAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Put).SendAsStringAsync(cancellationToken);
}
///
/// 发送 PUT 请求
///
///
///
public Task PutAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Put).SendAsync(cancellationToken);
}
///
/// 发送 DELETE 请求返回 T 对象
///
///
///
///
public Task DeleteAsAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Delete).SendAsAsync(cancellationToken);
}
///
/// 发送 DELETE 请求返回 Stream
///
///
///
public Task DeleteAsStreamAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Delete).SendAsStreamAsync(cancellationToken);
}
///
/// 发送 DELETE 请求返回 String
///
///
///
public Task DeleteAsStringAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Delete).SendAsStringAsync(cancellationToken);
}
///
/// 发送 DELETE 请求
///
///
///
public Task DeleteAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Delete).SendAsync(cancellationToken);
}
///
/// 发送 PATCH 请求返回 T 对象
///
///
///
///
public Task PatchAsAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Patch).SendAsAsync(cancellationToken);
}
///
/// 发送 PATCH 请求返回 Stream
///
///
///
public Task PatchAsStreamAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Patch).SendAsStreamAsync(cancellationToken);
}
///
/// 发送 Patch 请求返回 String
///
///
///
public Task PatchAsStringAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Patch).SendAsStringAsync(cancellationToken);
}
///
/// 发送 PATCH 请求
///
///
///
public Task PatchAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Patch).SendAsync(cancellationToken);
}
///
/// 发送 HEAD 请求返回 T 对象
///
///
///
///
public Task HeadAsAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Head).SendAsAsync(cancellationToken);
}
///
/// 发送 HEAD 请求返回 Stream
///
///
///
public Task HeadAsStreamAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Head).SendAsStreamAsync(cancellationToken);
}
///
/// 发送 Head 请求返回 String
///
///
///
public Task HeadAsStringAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Head).SendAsStringAsync(cancellationToken);
}
///
/// 发送 HEAD 请求
///
///
///
public Task HeadAsync(CancellationToken cancellationToken = default)
{
return SetHttpMethod(HttpMethod.Head).SendAsync(cancellationToken);
}
///
/// 发送请求返回 T 对象
///
///
///
///
public async Task SendAsAsync(CancellationToken cancellationToken = default)
{
// 如果 T 是 HttpResponseMessage 类型,则返回
if (typeof(T) == typeof(HttpResponseMessage))
{
var httpResponseMessage = await SendAsync(cancellationToken);
return (T)(object)httpResponseMessage;
}
if (typeof(T) == typeof(string))
{
var str = await SendAsStringAsync(cancellationToken);
return (T)(object)str;
}
// 读取流内容
var stream = await SendAsStreamAsync(cancellationToken);
if (stream == null) return default;
// 如果 T 是 Stream 类型,则返回
if (typeof(T) == typeof(Stream)) return (T)(object)stream;
using var streamReader = new StreamReader(stream);
var text = await streamReader.ReadToEndAsync();
// 释放流
await stream.DisposeAsync();
// 如果字符串为空,则返回默认值
if (string.IsNullOrWhiteSpace(text)) return default;
// 解析 Json 序列化提供器
var jsonSerializer = App.GetService(JsonSerializerProvider, RequestScoped ?? App.RootServices) as IJsonSerializerProvider;
// 反序列化流
var result = jsonSerializer.Deserialize(text, JsonSerializerOptions);
return result;
}
///
/// 发送请求返回 Stream
///
///
///
public async Task SendAsStreamAsync(CancellationToken cancellationToken = default)
{
var response = await SendAsync(cancellationToken);
if (response == null) return default;
// 读取响应流
var stream = await response.Content.ReadAsStreamAsync(cancellationToken);
return stream;
}
///
/// 发送请求返回 String
///
///
///
public async Task SendAsStringAsync(CancellationToken cancellationToken = default)
{
var response = await SendAsync(cancellationToken);
if (response == null) return default;
// 读取响应报文
var content = await response.Content.ReadAsStringAsync(cancellationToken);
return content;
}
///
/// 发送请求
///
///
///
public async Task SendAsync(CancellationToken cancellationToken = default)
{
// 检查是否配置了请求方法
if (Method == null) throw new NullReferenceException(nameof(Method));
// 检查请求地址,只有 Client 不配置才检查空
if (string.IsNullOrWhiteSpace(ClientName) && string.IsNullOrWhiteSpace(RequestUrl)) throw new NullReferenceException(RequestUrl);
// 处理模板问题
RequestUrl = RequestUrl.Render(Templates, true);
// 构建请求对象
var request = new HttpRequestMessage(Method, RequestUrl);
request.AppendQueries(Queries);
// 设置请求报文头
if (Headers != null)
{
foreach (var header in Headers)
{
if (header.Value != null) request.Headers.Add(header.Key, header.Value.ToString());
}
}
// 验证模型参数(只作用于 body 类型)
if (ValidationState.Enabled)
{
// 判断是否启用 Null 验证且 body 值为 null
if (ValidationState.IncludeNull && Body == null) throw new InvalidOperationException($"{nameof(Body)} can not be null.");
// 验证模型
Body?.Validate();
}
// 设置 HttpContent
SetHttpContent(request);
// 配置请求拦截
RequestInterceptors.ForEach(u =>
{
u?.Invoke(request);
});
// 创建客户端请求工厂
var clientFactory = App.GetService(RequestScoped ?? App.RootServices);
if (clientFactory == null) throw new InvalidOperationException("please add `services.AddRemoteRequest()` in Startup.cs.");
// 创建 HttpClient 对象
using var httpClient = string.IsNullOrWhiteSpace(ClientName)
? clientFactory.CreateClient()
: clientFactory.CreateClient(ClientName);
// 只有大于 0 才设置超时时间
if (Timeout > 0)
{
// 设置请求超时时间
httpClient.Timeout = TimeSpan.FromSeconds(Timeout);
}
// 判断命名客户端是否配置了 BaseAddress,且必须以 / 结尾
var httpClientOriginalString = httpClient.BaseAddress?.OriginalString;
if (!string.IsNullOrWhiteSpace(httpClientOriginalString) && !httpClientOriginalString.EndsWith("/"))
throw new InvalidOperationException($"The `{ClientName}` of HttpClient BaseAddress must be end with '/'.");
// 添加默认 User-Agent
if (!httpClient.DefaultRequestHeaders.Contains("User-Agent"))
{
httpClient.DefaultRequestHeaders.Add("User-Agent",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36 Edg/91.0.864.48");
}
// 配置 HttpClient 拦截
HttpClientInterceptors.ForEach(u =>
{
u?.Invoke(httpClient);
});
// 打印发送请求
App.PrintToMiniProfiler(MiniProfilerCategory, "Sending", $"[{Method}] {httpClientOriginalString}{request.RequestUri?.OriginalString}");
// 捕获异常
Exception exception = default;
HttpResponseMessage response = default;
try
{
if (RetryPolicy == null) response = await httpClient.SendAsync(request, cancellationToken);
else
{
// 失败重试
await Retry.Invoke(async () =>
{
// 发送请求
response = await httpClient.SendAsync(request, cancellationToken);
}, RetryPolicy.Value.NumRetries, RetryPolicy.Value.RetryTimeout);
}
}
catch (Exception ex)
{
// 触发自定义事件
OnRequestFailded(this, new HttpRequestFaildedEventArgs(request, response, ex));
exception = ex;
}
// 请求成功
if (response?.IsSuccessStatusCode == true && exception == default)
{
// 打印成功请求
App.PrintToMiniProfiler(MiniProfilerCategory, "Succeeded", $"[StatusCode: {response.StatusCode}] Succeeded");
// 调用成功拦截器
ResponseInterceptors.ForEach(u =>
{
u?.Invoke(response);
});
}
// 请求异常
else
{
// 读取错误消息
var errors = exception == null
? await response.Content.ReadAsStringAsync(cancellationToken)
: exception.Message;
// 打印失败请求
App.PrintToMiniProfiler(MiniProfilerCategory, "Failed", $"[StatusCode: {response?.StatusCode}] {errors}", true);
// 抛出异常
if (ExceptionInterceptors == null || ExceptionInterceptors.Count == 0) throw new HttpRequestException(errors);
// 调用异常拦截器
else ExceptionInterceptors.ForEach(u =>
{
u?.Invoke(response, errors);
});
}
return response;
}
///
/// 设置 HttpContent
///
///
private void SetHttpContent(HttpRequestMessage request)
{
// GET/HEAD 请求不支持设置 Body 请求
if (Method == HttpMethod.Get || Method == HttpMethod.Head) return;
HttpContent httpContent = null;
// 处理各种 Body 类型
switch (ContentType)
{
case "multipart/form-data":
var multipartFormDataContent = new MultipartFormDataContent();
// 添加 Bytes 类型
foreach (var (Name, Bytes, FileName) in BodyBytes)
{
if (string.IsNullOrWhiteSpace(FileName))
multipartFormDataContent.Add(new ByteArrayContent(Bytes), Name);
else
multipartFormDataContent.Add(new ByteArrayContent(Bytes), Name, FileName);
}
// 处理其他类型
var dic = ConvertBodyToDictionary();
if (dic != null && dic.Count > 0)
{
foreach (var (key, value) in dic)
{
multipartFormDataContent.Add(new StringContent(value, ContentEncoding), string.Format("\"{0}\"", key));
}
}
// 设置内容类型
multipartFormDataContent.Headers.ContentType = new MediaTypeHeaderValue(ContentType);
httpContent = multipartFormDataContent;
break;
case "application/octet-stream":
if (BodyBytes.Count > 0 && BodyBytes[0].Bytes.Length > 0)
{
httpContent = new ByteArrayContent(BodyBytes[0].Bytes);
// 设置内容类型
httpContent.Headers.ContentType = new MediaTypeHeaderValue(ContentType);
}
break;
case "application/json":
case "text/json":
case "application/*+json":
if (Body != null)
{
httpContent = new StringContent(SerializerObject(Body), ContentEncoding);
// 设置内容类型
httpContent.Headers.ContentType = new MediaTypeHeaderValue(ContentType);
}
break;
case "application/x-www-form-urlencoded":
// 解析字典
var keyValues = ConvertBodyToDictionary();
if (keyValues == null || keyValues.Count == 0) return;
// 设置内容类型
httpContent = new FormUrlEncodedContent(keyValues);
break;
case "application/xml":
case "text/xml":
if (Body != null) httpContent = new StringContent(Body.ToString(), ContentEncoding, ContentType);
break;
default:
// 其他类型可通过 `HttpRequestMessage` 拦截器设置
break;
}
// 设置 HttpContent
if (httpContent != null) request.Content = httpContent;
}
///
/// 转换 Body 为 字典类型
///
///
private IDictionary ConvertBodyToDictionary()
{
IDictionary keyValues = null;
if (Body == null) return default;
// 处理各种情况
if (Body is IDictionary dic) keyValues = dic;
else if (Body is IDictionary dicObj) keyValues = dicObj.ToDictionary(u => u.Key, u => SerializerObject(u.Value));
else keyValues = Body.ToDictionary().ToDictionary(u => u.Key, u => SerializerObject(u.Value));
return keyValues;
}
///
/// 序列化对象
///
///
///
private string SerializerObject(object body)
{
if (body == null) return default;
if (body is string) return body as string;
if (body.GetType().IsValueType) return body.ToString();
// 解析序列化工具
var jsonSerializer = App.GetService(JsonSerializerProvider, RequestScoped ?? App.RootServices) as IJsonSerializerProvider;
return jsonSerializer.Serialize(body, JsonSerializerOptions);
}
}
}