using MessagePack;
using Microsoft.AspNetCore.Mvc.Formatters;

namespace Dpz.Core.WebApi.MessagePackFormatters;

/// <summary>
/// formatter
/// </summary>
public class MessagePackInputFormatter : InputFormatter
{
    private readonly MessagePackSerializerOptions _options;
    private readonly SerializableTypesCache _serializableTypesCache;

    /// <summary>
    /// ctor
    /// </summary>
    /// <param name="options"></param>
    /// <param name="mediaTypes"></param>
    /// <exception cref="ArgumentNullException"></exception>
    /// <exception cref="ArgumentException"></exception>
    public MessagePackInputFormatter(
        MessagePackSerializerOptions options,
        ICollection<string> mediaTypes
    )
    {
        _options = options ?? throw new ArgumentNullException(nameof(options));
        if (mediaTypes == null)
        {
            throw new ArgumentNullException(nameof(mediaTypes));
        }

        if (mediaTypes.Count == 0)
        {
            throw new ArgumentException("Media type must be specified.", nameof(mediaTypes));
        }

        _serializableTypesCache = new SerializableTypesCache(options.Resolver);

        foreach (var mediaType in mediaTypes)
        {
            SupportedMediaTypes.Add(mediaType);
        }
    }

    /// <inheritdoc />
    public override async Task<InputFormatterResult> ReadRequestBodyAsync(
        InputFormatterContext context
    )
    {
        var httpContext = context.HttpContext;
        var result = await MessagePackSerializer.DeserializeAsync(
            context.ModelType,
            httpContext.Request.Body,
            _options,
            httpContext.RequestAborted
        );
        return await InputFormatterResult.SuccessAsync(result);
    }

    /// <inheritdoc />
    /// <exception cref="T:System.ArgumentNullException"><paramref name="type" /> is <c>null</c>.</exception>
    protected override bool CanReadType(Type type)
    {
        return _serializableTypesCache.CanSerialize(type);
    }
}
⚠⚠    以下内容为AI分析的结果,请根据实际情况进行判断。

这是一个基于MessagePack的ASP.NET Core输入格式化器(Input Formatter)实现。让我详细解释一下这个代码:

类的作用

MessagePackInputFormatter 继承自 InputFormatter,用于在ASP.NET Core Web API中处理MessagePack格式的HTTP请求体数据,将其反序列化为.NET对象。

核心组件

1. 私有字段

private readonly MessagePackSerializerOptions _options;
private readonly SerializableTypesCache _serializableTypesCache;
  • _options: MessagePack序列化器的配置选项
  • _serializableTypesCache: 用于缓存哪些类型可以被序列化的缓存对象

2. 构造函数

public MessagePackInputFormatter(
    MessagePackSerializerOptions options,
    ICollection<string> mediaTypes
)

功能

  • 接收MessagePack序列化选项和支持的媒体类型列表
  • 进行参数验证(null检查和空集合检查)
  • 初始化序列化类型缓存
  • 将传入的媒体类型添加到支持的媒体类型列表中

参数验证

  • 确保 options 不为null
  • 确保 mediaTypes 不为null且不为空
  • 如果验证失败会抛出相应的异常

3. 核心方法

ReadRequestBodyAsync方法

public override async Task<InputFormatterResult> ReadRequestBodyAsync(
    InputFormatterContext context
)

功能

  • 这是格式化器的核心方法,负责读取HTTP请求体并反序列化
  • 使用 MessagePackSerializer.DeserializeAsync 异步反序列化请求体
  • 支持取消令牌,可以响应请求取消

处理流程

  1. 获取HTTP上下文
  2. 调用MessagePack反序列化器处理请求体流
  3. 返回成功的格式化结果

CanReadType方法

protected override bool CanReadType(Type type)

功能

  • 判断指定的类型是否可以被这个格式化器处理
  • 通过 _serializableTypesCache 检查类型的可序列化性

使用场景

这个格式化器通常用于:

  1. 需要高性能序列化的API场景
  2. 二进制数据传输需求
  3. 跨语言通信(MessagePack支持多种编程语言)
  4. 数据量较大,需要压缩传输的场景

集成方式

通常在ASP.NET Core的Program.csStartup.cs中注册:

services.AddControllers(options =>
{
    options.InputFormatters.Add(new MessagePackInputFormatter(
        MessagePackSerializerOptions.Standard,
        new[] { "application/msgpack" }
    ));
});

这个实现提供了一个完整的MessagePack输入格式化解决方案,支持异步处理、类型验证和错误处理。

评论加载中...