网站首页 网站源码
using System.Buffers;
using Microsoft.Extensions.Primitives;
using Microsoft.IO;
#nullable enable
namespace Dpz.Core.WebApi.Middleware;
/// <summary>
/// DateTime 时间本地化处理
/// </summary>
public class DateTimeFormattingMiddleware(
RequestDelegate next,
ILogger<DateTimeFormattingMiddleware> logger
)
{
/// <summary>
/// handle datetime in response
/// </summary>
public async Task InvokeAsync(HttpContext context)
{
var originalBody = context.Response.Body;
try
{
await using var memoryStream = ApplicationTools.MemoryStreamManager.GetStream();
context.Response.Body = memoryStream;
await next(context);
var dataFormat = context.Request.Query["date_format"];
if (
context.Response is { StatusCode: StatusCodes.Status200OK, ContentType: not null }
&& context.Response.ContentType.Contains("application/json")
&& !StringValues.IsNullOrEmpty(dataFormat)
&& FormatDict.ContainsKey(dataFormat!)
)
{
memoryStream.Position = 0;
using var bodyReader = new StreamReader(memoryStream);
var originalResponseBody = await bodyReader.ReadToEndAsync();
var formattedResponseBodySequence = await FormatDateTimeInJsonAsync(
originalResponseBody,
dataFormat!
);
if (formattedResponseBodySequence != null)
{
// formattedResponseBodyBytes.Value
// await originalBody.WriteAsync();
foreach (var segment in formattedResponseBodySequence.Value)
{
await originalBody.WriteAsync(segment);
}
}
else
{
memoryStream.Position = 0;
await memoryStream.CopyToAsync(originalBody);
}
}
else
{
memoryStream.Position = 0;
await memoryStream.CopyToAsync(originalBody);
}
}
catch (Exception e)
{
logger.LogError(e, "Error occurred while formatting datetime in response.");
}
finally
{
context.Response.Body = originalBody;
}
}
private static readonly Dictionary<string, string> FormatDict =
new() { { "zh-cn", "yyyy-MM-dd HH:mm:ss" }, { "zh-date", "yyyy-MM-dd" }, };
private async Task<ReadOnlySequence<byte>?> FormatDateTimeInJsonAsync(
string jsonResponse,
string dateFormat
)
{
try
{
var jsonDocument = JsonDocument.Parse(jsonResponse);
await using Stream memoryStream = ApplicationTools.MemoryStreamManager.GetStream();
await using var writer = new Utf8JsonWriter(memoryStream);
WriteFormattedJson(writer, jsonDocument.RootElement, dateFormat);
await writer.FlushAsync();
return ((RecyclableMemoryStream)memoryStream).GetReadOnlySequence();
}
catch (Exception e)
{
logger.LogError(e, "Error occurred while formatting datetime in json.");
return null;
}
}
private void WriteFormattedJson(Utf8JsonWriter writer, JsonElement element, string dateFormat)
{
switch (element.ValueKind)
{
case JsonValueKind.Object:
writer.WriteStartObject();
foreach (var property in element.EnumerateObject())
{
if (
property.Value.ValueKind == JsonValueKind.String
&& DateTime.TryParse(property.Value.GetString(), out var dateTime)
&& FormatDict.TryGetValue(dateFormat, out var format)
)
{
var formattedDate = dateTime.ToString(format);
writer.WriteString(property.Name, formattedDate);
}
else
{
writer.WritePropertyName(property.Name);
WriteFormattedJson(writer, property.Value, dateFormat);
}
}
writer.WriteEndObject();
break;
case JsonValueKind.Array:
writer.WriteStartArray();
foreach (var item in element.EnumerateArray())
{
WriteFormattedJson(writer, item, dateFormat);
}
writer.WriteEndArray();
break;
default:
element.WriteTo(writer);
break;
}
}
}
上述代码实现了一个中间件 DateTimeFormattingMiddleware
,用于处理 ASP.NET Core 应用程序中的 HTTP 响应,特别是对 JSON 响应中的日期时间格式进行本地化处理。以下是代码的主要功能和工作原理的详细解释:
中间件结构:
DateTimeFormattingMiddleware
类实现了一个中间件,接收一个 RequestDelegate
和一个 ILogger
实例。处理请求和响应:
InvokeAsync
方法中,首先保存原始的响应流 originalBody
。MemoryStream
作为临时存储,重定向 context.Response.Body
到这个内存流,以便在处理请求后可以读取响应内容。日期格式化逻辑:
date_format
,并验证响应的状态码和内容类型。FormatDateTimeInJsonAsync
方法进行日期时间格式化。日期格式字典:
FormatDict
字典定义了支持的日期格式,例如中文格式 zh-cn
和 zh-date
。JSON 解析和格式化:
FormatDateTimeInJsonAsync
方法解析 JSON 响应,使用 Utf8JsonWriter
将格式化后的 JSON 写入内存流。WriteFormattedJson
方法递归遍历 JSON 元素,查找字符串类型的日期时间,并根据指定的格式进行格式化。错误处理:
ILogger
记录可能发生的错误,以便于调试和监控。InvokeAsync
方法被调用。这个中间件的主要目的是在 ASP.NET Core 应用程序中提供灵活的日期时间格式化功能,允许开发者根据请求参数动态调整 JSON 响应中的日期时间格式,以满足不同地区或用户的需求。