网站首页 网站源码
website
站点相关全部源代码,隐藏了一些关于服务器的信息
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;
        }
    }
}
⚠⚠    以下内容为AI分析的结果,请根据实际情况进行判断。

上述代码实现了一个中间件 DateTimeFormattingMiddleware,用于处理 ASP.NET Core 应用程序中的 HTTP 响应,特别是对 JSON 响应中的日期时间格式进行本地化处理。以下是代码的主要功能和工作原理的详细解释:

主要功能

  1. 中间件结构

    • DateTimeFormattingMiddleware 类实现了一个中间件,接收一个 RequestDelegate 和一个 ILogger 实例。
    • 中间件的主要任务是在 HTTP 响应中查找日期时间字符串,并根据请求中的参数格式化这些日期时间。
  2. 处理请求和响应

    • InvokeAsync 方法中,首先保存原始的响应流 originalBody
    • 使用 MemoryStream 作为临时存储,重定向 context.Response.Body 到这个内存流,以便在处理请求后可以读取响应内容。
  3. 日期格式化逻辑

    • 检查请求的查询参数 date_format,并验证响应的状态码和内容类型。
    • 如果满足条件,读取内存流中的原始 JSON 响应,并调用 FormatDateTimeInJsonAsync 方法进行日期时间格式化。
    • 如果格式化成功,将格式化后的内容写回原始响应流;如果失败,则将原始内容写回。
  4. 日期格式字典

    • FormatDict 字典定义了支持的日期格式,例如中文格式 zh-cnzh-date
  5. JSON 解析和格式化

    • FormatDateTimeInJsonAsync 方法解析 JSON 响应,使用 Utf8JsonWriter 将格式化后的 JSON 写入内存流。
    • WriteFormattedJson 方法递归遍历 JSON 元素,查找字符串类型的日期时间,并根据指定的格式进行格式化。
  6. 错误处理

    • 在整个过程中,使用 ILogger 记录可能发生的错误,以便于调试和监控。

工作流程

  1. 当请求到达时,InvokeAsync 方法被调用。
  2. 中间件将响应流重定向到内存流,并调用下一个中间件。
  3. 在响应完成后,检查是否需要格式化日期时间。
  4. 如果需要,解析 JSON,格式化日期时间,并将结果写回响应流。
  5. 最后,将响应流恢复为原始流,确保后续中间件或处理程序可以正常工作。

总结

这个中间件的主要目的是在 ASP.NET Core 应用程序中提供灵活的日期时间格式化功能,允许开发者根据请求参数动态调整 JSON 响应中的日期时间格式,以满足不同地区或用户的需求。

loading