Compare commits

...

4 Commits

52 changed files with 349 additions and 191 deletions

View File

@@ -13,7 +13,9 @@ body:
label:
description: 使 Furion
options:
- 4.9.7.217 ()
- 4.9.7.219 ()
- 4.9.7.218
- 4.9.7.217
- 4.9.7.216
- 4.9.7.215
- 4.9.7.214

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<LangVersion>preview</LangVersion>
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
<Version>4.9.7.217</Version>
<Version>4.9.7.219</Version>
<ImplicitUsings>enable</ImplicitUsings>
<!--<Nullable>enable</Nullable>-->
<Authors>百小僧</Authors>

View File

@@ -104,7 +104,7 @@ public static class StringUtility
// 获取字符串
var formatString = stringBuilder.ToString();
return hasSummary ? $"\e[34m\e[1m{summary}:\e[0m \r\n{formatString}" : formatString;
return hasSummary ? $"\e[36m\e[1m{summary}:\e[0m \r\n{formatString}" : formatString;
}
/// <summary>

View File

@@ -162,17 +162,25 @@ public sealed class HttpMultipartFormDataBuilder
/// <param name="name">表单名称。该值不为空时作为表单的一项。否则将遍历对象类型的每一个公开属性作为表单的项。</param>
/// <param name="contentEncoding">内容编码</param>
/// <param name="contentType">内容类型</param>
/// <param name="jsonSerializerOptions">
/// <see cref="JsonSerializerOptions" />
/// </param>
/// <returns>
/// <see cref="HttpMultipartFormDataBuilder" />
/// </returns>
/// <exception cref="JsonException"></exception>
public HttpMultipartFormDataBuilder AddJson(object? rawJson, string? name = null, Encoding? contentEncoding = null,
string? contentType = null)
string? contentType = null, JsonSerializerOptions? jsonSerializerOptions = null)
{
// 检查是否配置表单名或不是字符串类型
if (!string.IsNullOrWhiteSpace(name) || rawJson is not string rawString)
{
return AddObject(rawJson, name, contentType ?? MediaTypeNames.Application.Json, contentEncoding);
// 当传入 jsonSerializerOptions 参数时,直接进行序列化后再传入
var extractedJson = jsonSerializerOptions is null
? rawJson
: JsonSerializer.Serialize(rawJson, jsonSerializerOptions);
return AddObject(extractedJson, name, contentType ?? MediaTypeNames.Application.Json, contentEncoding);
}
// 尝试验证并获取 JsonDocument 实例(需 using
@@ -184,6 +192,27 @@ public sealed class HttpMultipartFormDataBuilder
return AddObject(jsonDocument, name, contentType ?? MediaTypeNames.Application.Json, contentEncoding);
}
/// <summary>
/// 添加 JSON 内容(宽松模式)
/// </summary>
/// <remarks>跳过对 JSON 字符串校验。</remarks>
/// <param name="rawJson">JSON 字符串</param>
/// <param name="name">表单名称</param>
/// <param name="contentEncoding">内容编码</param>
/// <param name="contentType">内容类型</param>
/// <returns>
/// <see cref="HttpMultipartFormDataBuilder" />
/// </returns>
public HttpMultipartFormDataBuilder AddJsonWithoutValidation(string? rawJson, string name,
Encoding? contentEncoding = null,
string? contentType = null)
{
// 空检查
ArgumentException.ThrowIfNullOrWhiteSpace(name);
return AddObject(rawJson, name, contentType ?? MediaTypeNames.Application.Json, contentEncoding);
}
/// <summary>
/// 添加单个表单项内容
/// </summary>
@@ -207,15 +236,17 @@ public sealed class HttpMultipartFormDataBuilder
/// <param name="htmlString">HTML 字符串</param>
/// <param name="name">表单名称</param>
/// <param name="contentEncoding">内容编码</param>
/// <param name="contentType">内容类型</param>
/// <returns>
/// <see cref="HttpMultipartFormDataBuilder" />
/// </returns>
public HttpMultipartFormDataBuilder AddHtml(string? htmlString, string name, Encoding? contentEncoding = null)
public HttpMultipartFormDataBuilder AddHtml(string? htmlString, string name, Encoding? contentEncoding = null,
string? contentType = null)
{
// 空检查
ArgumentException.ThrowIfNullOrWhiteSpace(name);
return AddObject(htmlString, name, MediaTypeNames.Text.Html, contentEncoding);
return AddObject(htmlString, name, contentType ?? MediaTypeNames.Text.Html, contentEncoding);
}
/// <summary>
@@ -243,15 +274,17 @@ public sealed class HttpMultipartFormDataBuilder
/// <param name="text">文本</param>
/// <param name="name">表单名称</param>
/// <param name="contentEncoding">内容编码</param>
/// <param name="contentType">内容类型</param>
/// <returns>
/// <see cref="HttpMultipartFormDataBuilder" />
/// </returns>
public HttpMultipartFormDataBuilder AddText(string? text, string name, Encoding? contentEncoding = null)
public HttpMultipartFormDataBuilder AddText(string? text, string name, Encoding? contentEncoding = null,
string? contentType = null)
{
// 空检查
ArgumentException.ThrowIfNullOrWhiteSpace(name);
return AddObject(text, name, MediaTypeNames.Text.Plain, contentEncoding);
return AddObject(text, name, contentType ?? MediaTypeNames.Text.Plain, contentEncoding);
}
/// <summary>

View File

@@ -165,16 +165,32 @@ public sealed partial class HttpRequestBuilder
return SetContent(jsonDocument, contentType ?? MediaTypeNames.Application.Json, contentEncoding);
}
/// <summary>
/// 设置 JSON 内容(宽松模式)
/// </summary>
/// <remarks>跳过对 JSON 字符串校验。</remarks>
/// <param name="rawJson">JSON 字符串</param>
/// <param name="contentEncoding">内容编码</param>
/// <param name="contentType">内容类型</param>
/// <returns>
/// <see cref="HttpRequestBuilder" />
/// </returns>
public HttpRequestBuilder SetJsonContentWithoutValidation(string? rawJson, Encoding? contentEncoding = null,
string? contentType = null) =>
SetContent(rawJson, contentType ?? MediaTypeNames.Application.Json, contentEncoding);
/// <summary>
/// 设置 HTML 内容
/// </summary>
/// <param name="htmlString">HTML 字符串</param>
/// <param name="contentEncoding">内容编码</param>
/// <param name="contentType">内容类型</param>
/// <returns>
/// <see cref="HttpRequestBuilder" />
/// </returns>
public HttpRequestBuilder SetHtmlContent(string? htmlString, Encoding? contentEncoding = null) =>
SetContent(htmlString, MediaTypeNames.Text.Html, contentEncoding);
public HttpRequestBuilder SetHtmlContent(string? htmlString, Encoding? contentEncoding = null,
string? contentType = null) =>
SetContent(htmlString, contentType ?? MediaTypeNames.Text.Html, contentEncoding);
/// <summary>
/// 设置 XML 内容
@@ -186,19 +202,20 @@ public sealed partial class HttpRequestBuilder
/// <see cref="HttpRequestBuilder" />
/// </returns>
public HttpRequestBuilder SetXmlContent(string? xmlString, Encoding? contentEncoding = null,
string? contentType = null) =>
SetContent(xmlString, contentType ?? MediaTypeNames.Text.Xml, contentEncoding);
string? contentType = null) => SetContent(xmlString, contentType ?? MediaTypeNames.Text.Xml, contentEncoding);
/// <summary>
/// 设置文本内容
/// </summary>
/// <param name="text">文本</param>
/// <param name="contentEncoding">内容编码</param>
/// <param name="contentType">内容类型</param>
/// <returns>
/// <see cref="HttpRequestBuilder" />
/// </returns>
public HttpRequestBuilder SetTextContent(string? text, Encoding? contentEncoding = null) =>
SetContent(text, MediaTypeNames.Text.Plain, contentEncoding);
public HttpRequestBuilder
SetTextContent(string? text, Encoding? contentEncoding = null, string? contentType = null) =>
SetContent(text, contentType ?? MediaTypeNames.Text.Plain, contentEncoding);
/// <summary>
/// 设置原始字符串内容

View File

@@ -96,6 +96,12 @@ internal static class Constants
/// <remarks>被用于从 <see cref="HttpRequestMessage" /> 的 <c>Options</c> 属性中读取。</remarks>
internal const string DISABLE_PROFILER_KEY = "__DISABLE_PROFILER__";
/// <summary>
/// 请求分析工具打印标识键
/// </summary>
/// <remarks>解决重复打印问题。被用于从 <see cref="HttpRequestMessage" /> 的 <c>Options</c> 属性中读取。</remarks>
internal const string PROFILER_PRINTED_KEY = "__PROFILER_PRINTED__";
/// <summary>
/// 启用 JSON 响应反序列化包装器键
/// </summary>

View File

@@ -55,9 +55,18 @@ public sealed class ProfilerDelegatingHandler(IHttpRemoteLogger logger, IOptions
/// <returns>
/// <see cref="bool" />
/// </returns>
internal static bool IsEnabled(HttpRequestMessage httpRequestMessage) =>
!(httpRequestMessage.Options.TryGetValue(new HttpRequestOptionsKey<string>(Constants.DISABLE_PROFILER_KEY),
out var value) && value == "TRUE");
internal static bool IsEnabled(HttpRequestMessage httpRequestMessage)
{
// 检查是否已打印过
if (httpRequestMessage.Options.TryGetValue(new HttpRequestOptionsKey<string>(Constants.PROFILER_PRINTED_KEY),
out _))
{
return false;
}
return !(httpRequestMessage.Options.TryGetValue(
new HttpRequestOptionsKey<string>(Constants.DISABLE_PROFILER_KEY), out var value) && value == "TRUE");
}
/// <inheritdoc />
protected override HttpResponseMessage Send(HttpRequestMessage httpRequestMessage,

View File

@@ -243,7 +243,10 @@ public static partial class HttpRemoteExtensions
[httpRequestMessage.RequestUri?.OriginalString!]),
new KeyValuePair<string, IEnumerable<string>>("HTTP Method", [httpRequestMessage.Method.ToString()]),
new KeyValuePair<string, IEnumerable<string>>("Status Code",
[httpResponseMessage.GetColoredStatusText()]),
[
httpResponseMessage.GetColoredText(
$"{(int)httpResponseMessage.StatusCode} {httpResponseMessage.StatusCode}")
]),
new KeyValuePair<string, IEnumerable<string>>("HTTP Version", [httpResponseMessage.Version.ToString()]),
new KeyValuePair<string, IEnumerable<string>>("HTTP Content",
[$"{httpContent?.GetType().Name}"])
@@ -256,47 +259,6 @@ public static partial class HttpRemoteExtensions
return $"{generalEntry}\r\n{responseEntry}";
}
/// <summary>
/// 获取带颜色的 HTTP 状态码文本
/// </summary>
/// <param name="httpResponseMessage">
/// <see cref="HttpResponseMessage" />
/// </param>
/// <returns>
/// <see cref="string" />
/// </returns>
internal static string GetColoredStatusText(this HttpResponseMessage httpResponseMessage)
{
// 空检查
ArgumentNullException.ThrowIfNull(httpResponseMessage);
// 初始化 StringBuilder 实例
var stringBuilder = new StringBuilder();
// 检查是否是成功请求状态码
if (httpResponseMessage.IsSuccessStatusCode)
{
// 输出绿色内容
stringBuilder.Append("\e[32m");
}
else
{
// 检查是否是重定向状态码
stringBuilder.Append(httpResponseMessage.StatusCode is HttpStatusCode.Ambiguous or HttpStatusCode.Moved
or HttpStatusCode.Redirect
or HttpStatusCode.RedirectMethod
// 输出黄色内容
? "\e[33m"
// 输出红色内容
: "\e[31m");
}
// 追加完整内容
stringBuilder.Append($"\e[1m{(int)httpResponseMessage.StatusCode} {httpResponseMessage.StatusCode}\e[0m");
return stringBuilder.ToString();
}
/// <summary>
/// 分析 <see cref="HttpContent" /> 内容
/// </summary>
@@ -362,24 +324,72 @@ public static partial class HttpRemoteExtensions
partialContent = Regex.Unescape(partialContent);
}
// 检查响应是否为失败状态
if (httpResponseMessage is not null && !httpResponseMessage.IsSuccessStatusCode)
// 检查
if (httpResponseMessage is not null)
{
// 输出带颜色的内容:重定向(黄色),其他(红色)
partialContent =
$"{(httpResponseMessage.StatusCode is HttpStatusCode.Ambiguous or HttpStatusCode.Moved or HttpStatusCode.Redirect or HttpStatusCode.RedirectMethod ? "\e[33m" : "\e[31m")}\e[1m{partialContent}\e[0m";
// 对响应内容进行着色
partialContent = httpResponseMessage.GetColoredText(partialContent, false);
}
// 如果实际读取的数据小于最大显示大小,则直接返回;否则,添加省略号表示内容被截断
var bodyString = total <= maxBytesToDisplay
? partialContent
: partialContent + $"\e[32m\e[1m ... [truncated, total: {total} bytes]\e[0m";
: partialContent + $"\e[36m\e[1m ... [truncated, total: {total} bytes]\e[0m";
return StringUtility.FormatKeyValuesSummary(
[new KeyValuePair<string, IEnumerable<string>>(string.Empty, [bodyString])],
$"{summary} ({httpContent.GetType().Name}, total: {total} bytes)");
}
/// <summary>
/// 获取带颜色的文本
/// </summary>
/// <param name="httpResponseMessage">
/// <see cref="HttpResponseMessage" />
/// </param>
/// <param name="text">文本</param>
/// <param name="bold">是否加粗显示</param>
/// <returns>
/// <see cref="string" />
/// </returns>
internal static string GetColoredText(this HttpResponseMessage httpResponseMessage, string? text, bool bold = true)
{
// 空检查
ArgumentNullException.ThrowIfNull(httpResponseMessage);
// 初始化 StringBuilder 实例
var stringBuilder = new StringBuilder();
// 检查是否是成功请求状态码
if (httpResponseMessage.IsSuccessStatusCode)
{
// 输出绿色内容
stringBuilder.Append("\e[32m");
}
else
{
// 检查是否是重定向状态码
stringBuilder.Append(httpResponseMessage.StatusCode is HttpStatusCode.Ambiguous or HttpStatusCode.Moved
or HttpStatusCode.Redirect
or HttpStatusCode.RedirectMethod
// 输出黄色内容
? "\e[33m"
// 输出红色内容
: "\e[31m");
}
// 加粗处理
if (bold)
{
stringBuilder.Append("\e[1m");
}
// 追加完整内容
stringBuilder.Append($"{text}\e[0m");
return stringBuilder.ToString();
}
/// <summary>
/// 克隆 <see cref="HttpRequestMessage" />
/// </summary>

View File

@@ -456,6 +456,9 @@ internal sealed partial class HttpRemoteService : IHttpRemoteService
// 检查是否启用请求分析工具
if (httpRequestBuilder.ProfilerEnabled)
{
// 标记已打印,解决重复打印问题
httpRequestMessage.Options.TryAdd(Constants.PROFILER_PRINTED_KEY, "TRUE");
// 初始化 HttpRemoteAnalyzer 实例
httpRemoteAnalyzer = httpRequestBuilder.ProfilerPredicate is not null ? new HttpRemoteAnalyzer() : null;

View File

@@ -104,7 +104,7 @@ public static class StringUtility
// 获取字符串
var formatString = stringBuilder.ToString();
return hasSummary ? $"\e[34m\e[1m{summary}:\e[0m \r\n{formatString}" : formatString;
return hasSummary ? $"\e[36m\e[1m{summary}:\e[0m \r\n{formatString}" : formatString;
}
/// <summary>

View File

@@ -162,17 +162,25 @@ public sealed class HttpMultipartFormDataBuilder
/// <param name="name">表单名称。该值不为空时作为表单的一项。否则将遍历对象类型的每一个公开属性作为表单的项。</param>
/// <param name="contentEncoding">内容编码</param>
/// <param name="contentType">内容类型</param>
/// <param name="jsonSerializerOptions">
/// <see cref="JsonSerializerOptions" />
/// </param>
/// <returns>
/// <see cref="HttpMultipartFormDataBuilder" />
/// </returns>
/// <exception cref="JsonException"></exception>
public HttpMultipartFormDataBuilder AddJson(object? rawJson, string? name = null, Encoding? contentEncoding = null,
string? contentType = null)
string? contentType = null, JsonSerializerOptions? jsonSerializerOptions = null)
{
// 检查是否配置表单名或不是字符串类型
if (!string.IsNullOrWhiteSpace(name) || rawJson is not string rawString)
{
return AddObject(rawJson, name, contentType ?? MediaTypeNames.Application.Json, contentEncoding);
// 当传入 jsonSerializerOptions 参数时,直接进行序列化后再传入
var extractedJson = jsonSerializerOptions is null
? rawJson
: JsonSerializer.Serialize(rawJson, jsonSerializerOptions);
return AddObject(extractedJson, name, contentType ?? MediaTypeNames.Application.Json, contentEncoding);
}
// 尝试验证并获取 JsonDocument 实例(需 using
@@ -184,6 +192,27 @@ public sealed class HttpMultipartFormDataBuilder
return AddObject(jsonDocument, name, contentType ?? MediaTypeNames.Application.Json, contentEncoding);
}
/// <summary>
/// 添加 JSON 内容(宽松模式)
/// </summary>
/// <remarks>跳过对 JSON 字符串校验。</remarks>
/// <param name="rawJson">JSON 字符串</param>
/// <param name="name">表单名称</param>
/// <param name="contentEncoding">内容编码</param>
/// <param name="contentType">内容类型</param>
/// <returns>
/// <see cref="HttpMultipartFormDataBuilder" />
/// </returns>
public HttpMultipartFormDataBuilder AddJsonWithoutValidation(string? rawJson, string name,
Encoding? contentEncoding = null,
string? contentType = null)
{
// 空检查
ArgumentException.ThrowIfNullOrWhiteSpace(name);
return AddObject(rawJson, name, contentType ?? MediaTypeNames.Application.Json, contentEncoding);
}
/// <summary>
/// 添加单个表单项内容
/// </summary>
@@ -207,15 +236,17 @@ public sealed class HttpMultipartFormDataBuilder
/// <param name="htmlString">HTML 字符串</param>
/// <param name="name">表单名称</param>
/// <param name="contentEncoding">内容编码</param>
/// <param name="contentType">内容类型</param>
/// <returns>
/// <see cref="HttpMultipartFormDataBuilder" />
/// </returns>
public HttpMultipartFormDataBuilder AddHtml(string? htmlString, string name, Encoding? contentEncoding = null)
public HttpMultipartFormDataBuilder AddHtml(string? htmlString, string name, Encoding? contentEncoding = null,
string? contentType = null)
{
// 空检查
ArgumentException.ThrowIfNullOrWhiteSpace(name);
return AddObject(htmlString, name, MediaTypeNames.Text.Html, contentEncoding);
return AddObject(htmlString, name, contentType ?? MediaTypeNames.Text.Html, contentEncoding);
}
/// <summary>
@@ -243,15 +274,17 @@ public sealed class HttpMultipartFormDataBuilder
/// <param name="text">文本</param>
/// <param name="name">表单名称</param>
/// <param name="contentEncoding">内容编码</param>
/// <param name="contentType">内容类型</param>
/// <returns>
/// <see cref="HttpMultipartFormDataBuilder" />
/// </returns>
public HttpMultipartFormDataBuilder AddText(string? text, string name, Encoding? contentEncoding = null)
public HttpMultipartFormDataBuilder AddText(string? text, string name, Encoding? contentEncoding = null,
string? contentType = null)
{
// 空检查
ArgumentException.ThrowIfNullOrWhiteSpace(name);
return AddObject(text, name, MediaTypeNames.Text.Plain, contentEncoding);
return AddObject(text, name, contentType ?? MediaTypeNames.Text.Plain, contentEncoding);
}
/// <summary>

View File

@@ -165,16 +165,32 @@ public sealed partial class HttpRequestBuilder
return SetContent(jsonDocument, contentType ?? MediaTypeNames.Application.Json, contentEncoding);
}
/// <summary>
/// 设置 JSON 内容(宽松模式)
/// </summary>
/// <remarks>跳过对 JSON 字符串校验。</remarks>
/// <param name="rawJson">JSON 字符串</param>
/// <param name="contentEncoding">内容编码</param>
/// <param name="contentType">内容类型</param>
/// <returns>
/// <see cref="HttpRequestBuilder" />
/// </returns>
public HttpRequestBuilder SetJsonContentWithoutValidation(string? rawJson, Encoding? contentEncoding = null,
string? contentType = null) =>
SetContent(rawJson, contentType ?? MediaTypeNames.Application.Json, contentEncoding);
/// <summary>
/// 设置 HTML 内容
/// </summary>
/// <param name="htmlString">HTML 字符串</param>
/// <param name="contentEncoding">内容编码</param>
/// <param name="contentType">内容类型</param>
/// <returns>
/// <see cref="HttpRequestBuilder" />
/// </returns>
public HttpRequestBuilder SetHtmlContent(string? htmlString, Encoding? contentEncoding = null) =>
SetContent(htmlString, MediaTypeNames.Text.Html, contentEncoding);
public HttpRequestBuilder SetHtmlContent(string? htmlString, Encoding? contentEncoding = null,
string? contentType = null) =>
SetContent(htmlString, contentType ?? MediaTypeNames.Text.Html, contentEncoding);
/// <summary>
/// 设置 XML 内容
@@ -186,19 +202,20 @@ public sealed partial class HttpRequestBuilder
/// <see cref="HttpRequestBuilder" />
/// </returns>
public HttpRequestBuilder SetXmlContent(string? xmlString, Encoding? contentEncoding = null,
string? contentType = null) =>
SetContent(xmlString, contentType ?? MediaTypeNames.Text.Xml, contentEncoding);
string? contentType = null) => SetContent(xmlString, contentType ?? MediaTypeNames.Text.Xml, contentEncoding);
/// <summary>
/// 设置文本内容
/// </summary>
/// <param name="text">文本</param>
/// <param name="contentEncoding">内容编码</param>
/// <param name="contentType">内容类型</param>
/// <returns>
/// <see cref="HttpRequestBuilder" />
/// </returns>
public HttpRequestBuilder SetTextContent(string? text, Encoding? contentEncoding = null) =>
SetContent(text, MediaTypeNames.Text.Plain, contentEncoding);
public HttpRequestBuilder
SetTextContent(string? text, Encoding? contentEncoding = null, string? contentType = null) =>
SetContent(text, contentType ?? MediaTypeNames.Text.Plain, contentEncoding);
/// <summary>
/// 设置原始字符串内容

View File

@@ -96,6 +96,12 @@ internal static class Constants
/// <remarks>被用于从 <see cref="HttpRequestMessage" /> 的 <c>Options</c> 属性中读取。</remarks>
internal const string DISABLE_PROFILER_KEY = "__DISABLE_PROFILER__";
/// <summary>
/// 请求分析工具打印标识键
/// </summary>
/// <remarks>解决重复打印问题。被用于从 <see cref="HttpRequestMessage" /> 的 <c>Options</c> 属性中读取。</remarks>
internal const string PROFILER_PRINTED_KEY = "__PROFILER_PRINTED__";
/// <summary>
/// 启用 JSON 响应反序列化包装器键
/// </summary>

View File

@@ -55,9 +55,18 @@ public sealed class ProfilerDelegatingHandler(IHttpRemoteLogger logger, IOptions
/// <returns>
/// <see cref="bool" />
/// </returns>
internal static bool IsEnabled(HttpRequestMessage httpRequestMessage) =>
!(httpRequestMessage.Options.TryGetValue(new HttpRequestOptionsKey<string>(Constants.DISABLE_PROFILER_KEY),
out var value) && value == "TRUE");
internal static bool IsEnabled(HttpRequestMessage httpRequestMessage)
{
// 检查是否已打印过
if (httpRequestMessage.Options.TryGetValue(new HttpRequestOptionsKey<string>(Constants.PROFILER_PRINTED_KEY),
out _))
{
return false;
}
return !(httpRequestMessage.Options.TryGetValue(
new HttpRequestOptionsKey<string>(Constants.DISABLE_PROFILER_KEY), out var value) && value == "TRUE");
}
/// <inheritdoc />
protected override HttpResponseMessage Send(HttpRequestMessage httpRequestMessage,

View File

@@ -243,7 +243,10 @@ public static partial class HttpRemoteExtensions
[httpRequestMessage.RequestUri?.OriginalString!]),
new KeyValuePair<string, IEnumerable<string>>("HTTP Method", [httpRequestMessage.Method.ToString()]),
new KeyValuePair<string, IEnumerable<string>>("Status Code",
[httpResponseMessage.GetColoredStatusText()]),
[
httpResponseMessage.GetColoredText(
$"{(int)httpResponseMessage.StatusCode} {httpResponseMessage.StatusCode}")
]),
new KeyValuePair<string, IEnumerable<string>>("HTTP Version", [httpResponseMessage.Version.ToString()]),
new KeyValuePair<string, IEnumerable<string>>("HTTP Content",
[$"{httpContent?.GetType().Name}"])
@@ -256,47 +259,6 @@ public static partial class HttpRemoteExtensions
return $"{generalEntry}\r\n{responseEntry}";
}
/// <summary>
/// 获取带颜色的 HTTP 状态码文本
/// </summary>
/// <param name="httpResponseMessage">
/// <see cref="HttpResponseMessage" />
/// </param>
/// <returns>
/// <see cref="string" />
/// </returns>
internal static string GetColoredStatusText(this HttpResponseMessage httpResponseMessage)
{
// 空检查
ArgumentNullException.ThrowIfNull(httpResponseMessage);
// 初始化 StringBuilder 实例
var stringBuilder = new StringBuilder();
// 检查是否是成功请求状态码
if (httpResponseMessage.IsSuccessStatusCode)
{
// 输出绿色内容
stringBuilder.Append("\e[32m");
}
else
{
// 检查是否是重定向状态码
stringBuilder.Append(httpResponseMessage.StatusCode is HttpStatusCode.Ambiguous or HttpStatusCode.Moved
or HttpStatusCode.Redirect
or HttpStatusCode.RedirectMethod
// 输出黄色内容
? "\e[33m"
// 输出红色内容
: "\e[31m");
}
// 追加完整内容
stringBuilder.Append($"\e[1m{(int)httpResponseMessage.StatusCode} {httpResponseMessage.StatusCode}\e[0m");
return stringBuilder.ToString();
}
/// <summary>
/// 分析 <see cref="HttpContent" /> 内容
/// </summary>
@@ -362,24 +324,72 @@ public static partial class HttpRemoteExtensions
partialContent = Regex.Unescape(partialContent);
}
// 检查响应是否为失败状态
if (httpResponseMessage is not null && !httpResponseMessage.IsSuccessStatusCode)
// 检查
if (httpResponseMessage is not null)
{
// 输出带颜色的内容:重定向(黄色),其他(红色)
partialContent =
$"{(httpResponseMessage.StatusCode is HttpStatusCode.Ambiguous or HttpStatusCode.Moved or HttpStatusCode.Redirect or HttpStatusCode.RedirectMethod ? "\e[33m" : "\e[31m")}\e[1m{partialContent}\e[0m";
// 对响应内容进行着色
partialContent = httpResponseMessage.GetColoredText(partialContent, false);
}
// 如果实际读取的数据小于最大显示大小,则直接返回;否则,添加省略号表示内容被截断
var bodyString = total <= maxBytesToDisplay
? partialContent
: partialContent + $"\e[32m\e[1m ... [truncated, total: {total} bytes]\e[0m";
: partialContent + $"\e[36m\e[1m ... [truncated, total: {total} bytes]\e[0m";
return StringUtility.FormatKeyValuesSummary(
[new KeyValuePair<string, IEnumerable<string>>(string.Empty, [bodyString])],
$"{summary} ({httpContent.GetType().Name}, total: {total} bytes)");
}
/// <summary>
/// 获取带颜色的文本
/// </summary>
/// <param name="httpResponseMessage">
/// <see cref="HttpResponseMessage" />
/// </param>
/// <param name="text">文本</param>
/// <param name="bold">是否加粗显示</param>
/// <returns>
/// <see cref="string" />
/// </returns>
internal static string GetColoredText(this HttpResponseMessage httpResponseMessage, string? text, bool bold = true)
{
// 空检查
ArgumentNullException.ThrowIfNull(httpResponseMessage);
// 初始化 StringBuilder 实例
var stringBuilder = new StringBuilder();
// 检查是否是成功请求状态码
if (httpResponseMessage.IsSuccessStatusCode)
{
// 输出绿色内容
stringBuilder.Append("\e[32m");
}
else
{
// 检查是否是重定向状态码
stringBuilder.Append(httpResponseMessage.StatusCode is HttpStatusCode.Ambiguous or HttpStatusCode.Moved
or HttpStatusCode.Redirect
or HttpStatusCode.RedirectMethod
// 输出黄色内容
? "\e[33m"
// 输出红色内容
: "\e[31m");
}
// 加粗处理
if (bold)
{
stringBuilder.Append("\e[1m");
}
// 追加完整内容
stringBuilder.Append($"{text}\e[0m");
return stringBuilder.ToString();
}
/// <summary>
/// 克隆 <see cref="HttpRequestMessage" />
/// </summary>

View File

@@ -456,6 +456,9 @@ internal sealed partial class HttpRemoteService : IHttpRemoteService
// 检查是否启用请求分析工具
if (httpRequestBuilder.ProfilerEnabled)
{
// 标记已打印,解决重复打印问题
httpRequestMessage.Options.TryAdd(Constants.PROFILER_PRINTED_KEY, "TRUE");
// 初始化 HttpRemoteAnalyzer 实例
httpRemoteAnalyzer = httpRequestBuilder.ProfilerPredicate is not null ? new HttpRemoteAnalyzer() : null;

View File

@@ -11,8 +11,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.219" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.219" />
</ItemGroup>
<ItemGroup>

View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Furion.Template.Api</id>
<version>4.9.7.217</version>
<version>4.9.7.219</version>
<description>基于 Furion 框架快速搭建 Api 多层架构模板。</description>
<authors>百小僧</authors>
<packageTypes>

View File

@@ -12,9 +12,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Furion" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.217" />
<PackageReference Include="Furion" Version="4.9.7.219" />
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.219" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.219" />
</ItemGroup>
</Project>

View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Furion.Template.App</id>
<version>4.9.7.217</version>
<version>4.9.7.219</version>
<description>基于 Furion 框架快速搭建 Mvc/Api 多层架构模板。</description>
<authors>百小僧</authors>
<packageTypes>

View File

@@ -12,9 +12,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Furion" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.217" />
<PackageReference Include="Furion" Version="4.9.7.219" />
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.219" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.219" />
</ItemGroup>
</Project>

View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Furion.Template.Blazor.App</id>
<version>4.9.7.217</version>
<version>4.9.7.219</version>
<description>基于 Furion 框架快速搭建 Blazor App 多层架构模板。</description>
<authors>百小僧</authors>
<packageTypes>

View File

@@ -7,8 +7,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Furion" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.217" />
<PackageReference Include="Furion" Version="4.9.7.219" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.219" />
</ItemGroup>
</Project>

View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Furion.Template.Blazor</id>
<version>4.9.7.217</version>
<version>4.9.7.219</version>
<description>基于 Furion 框架快速搭建 Blazor 多层架构模板。</description>
<authors>百小僧</authors>
<packageTypes>

View File

@@ -7,8 +7,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Furion" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.217" />
<PackageReference Include="Furion" Version="4.9.7.219" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.219" />
</ItemGroup>
</Project>

View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Furion.Template.BlazorWithWebApi</id>
<version>4.9.7.217</version>
<version>4.9.7.219</version>
<description>基于 Furion 框架快速搭建 Blazor和WebApi 多层架构模板。</description>
<authors>百小僧</authors>
<packageTypes>

View File

@@ -12,9 +12,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Furion" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.217" />
<PackageReference Include="Furion" Version="4.9.7.219" />
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.219" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.219" />
</ItemGroup>
</Project>

View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Furion.Template.Mvc</id>
<version>4.9.7.217</version>
<version>4.9.7.219</version>
<description>基于 Furion 框架快速搭建 Mvc 多层架构模板。</description>
<authors>百小僧</authors>
<packageTypes>

View File

@@ -7,8 +7,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Furion" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.217" />
<PackageReference Include="Furion" Version="4.9.7.219" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.219" />
</ItemGroup>
</Project>

View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Furion.Template.Razor</id>
<version>4.9.7.217</version>
<version>4.9.7.219</version>
<description>基于 Furion 框架快速搭建 Razor Pages 多层架构模板。</description>
<authors>百小僧</authors>
<packageTypes>

View File

@@ -7,8 +7,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Furion" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.217" />
<PackageReference Include="Furion" Version="4.9.7.219" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.219" />
</ItemGroup>
</Project>

View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Furion.Template.RazorWithWebApi</id>
<version>4.9.7.217</version>
<version>4.9.7.219</version>
<description>基于 Furion 框架快速搭建 RazorPages和WebApi 多层架构模板。</description>
<authors>百小僧</authors>
<packageTypes>

View File

@@ -12,9 +12,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Furion" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.217" />
<PackageReference Include="Furion" Version="4.9.7.219" />
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.219" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.219" />
</ItemGroup>
</Project>

View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Furion.SqlSugar.Template.Api</id>
<version>4.9.7.217</version>
<version>4.9.7.219</version>
<description>基于 Furion 和 SqlSugar 框架快速搭建 Api 多层架构模板。</description>
<authors>百小僧</authors>
<packageTypes>

View File

@@ -12,9 +12,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.217" />
<PackageReference Include="Furion.Pure" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.219" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.219" />
<PackageReference Include="Furion.Pure" Version="4.9.7.219" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.210" />
</ItemGroup>

View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Furion.SqlSugar.Template.App</id>
<version>4.9.7.217</version>
<version>4.9.7.219</version>
<description>基于 Furion 和 SqlSugar 框架快速搭建 Mvc/Api 多层架构模板。</description>
<authors>百小僧</authors>
<packageTypes>

View File

@@ -12,9 +12,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.217" />
<PackageReference Include="Furion.Pure" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.219" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.219" />
<PackageReference Include="Furion.Pure" Version="4.9.7.219" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.210" />
</ItemGroup>

View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Furion.SqlSugar.Template.Blazor.App</id>
<version>4.9.7.217</version>
<version>4.9.7.219</version>
<description>基于 Furion 和 SqlSugar 框架快速搭建 Blazor App 多层架构模板。</description>
<authors>百小僧</authors>
<packageTypes>

View File

@@ -7,9 +7,9 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Furion.Pure" Version="4.9.7.217" />
<PackageReference Include="Furion.Pure" Version="4.9.7.219" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.210" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.219" />
</ItemGroup>
</Project>

View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Furion.SqlSugar.Template.Blazor</id>
<version>4.9.7.217</version>
<version>4.9.7.219</version>
<description>基于 Furion 和 SqlSugar 框架快速搭建 Blazor 多层架构模板。</description>
<authors>百小僧</authors>
<packageTypes>

View File

@@ -7,8 +7,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.217" />
<PackageReference Include="Furion.Pure" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.219" />
<PackageReference Include="Furion.Pure" Version="4.9.7.219" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.210" />
</ItemGroup>

View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Furion.SqlSugar.Template.BlazorWithWebApi</id>
<version>4.9.7.217</version>
<version>4.9.7.219</version>
<description>基于 Furion 和 SqlSugar 框架快速搭建 Blazor和WebApi 多层架构模板。</description>
<authors>百小僧</authors>
<packageTypes>

View File

@@ -12,9 +12,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.217" />
<PackageReference Include="Furion.Pure" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.219" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.219" />
<PackageReference Include="Furion.Pure" Version="4.9.7.219" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.210" />
</ItemGroup>

View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Furion.SqlSugar.Template.Mvc</id>
<version>4.9.7.217</version>
<version>4.9.7.219</version>
<description>基于 Furion 和 SqlSugar 框架快速搭建 Mvc 多层架构模板。</description>
<authors>百小僧</authors>
<packageTypes>

View File

@@ -7,8 +7,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.217" />
<PackageReference Include="Furion.Pure" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.219" />
<PackageReference Include="Furion.Pure" Version="4.9.7.219" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.210" />
</ItemGroup>

View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Furion.SqlSugar.Template.Razor</id>
<version>4.9.7.217</version>
<version>4.9.7.219</version>
<description>基于 Furion 和 SqlSugar 框架快速搭建 Razor Pages 多层架构模板。</description>
<authors>百小僧</authors>
<packageTypes>

View File

@@ -7,8 +7,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.217" />
<PackageReference Include="Furion.Pure" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.219" />
<PackageReference Include="Furion.Pure" Version="4.9.7.219" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.210" />
</ItemGroup>

View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Furion.SqlSugar.Template.RazorWithWebApi</id>
<version>4.9.7.217</version>
<version>4.9.7.219</version>
<description>基于 Furion 和 SqlSugar 框架快速搭建 RazorPages和WebApi 多层架构模板。</description>
<authors>百小僧</authors>
<packageTypes>

View File

@@ -12,9 +12,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.217" />
<PackageReference Include="Furion.Pure" Version="4.9.7.217" />
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.219" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.219" />
<PackageReference Include="Furion.Pure" Version="4.9.7.219" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.210" />
</ItemGroup>

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<LangVersion>preview</LangVersion>
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
<Version>4.9.7.217</Version>
<Version>4.9.7.219</Version>
<ImplicitUsings>enable</ImplicitUsings>
<!--<Nullable>enable</Nullable>-->
<Authors>百小僧</Authors>

View File

@@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Furion.Tools.CommandLine" Version="4.9.7.217" />
<PackageReference Include="Furion.Tools.CommandLine" Version="4.9.7.219" />
</ItemGroup>
</Project>

View File

@@ -96,7 +96,7 @@ function AddXmlCommentsToProperties($content, $commentsDictionary) {
return $modifiedContent
}
$FurTools = "Furion Tools v4.9.7.217";
$FurTools = "Furion Tools v4.9.7.219";
#
$copyright = @"