You need to enable JavaScript to run this app. C# 如何在自定义ActionFilter中根据类名字符串做类型转换?
优惠活动
大模型
产品
解决方案
定价
更多

C# 如何在自定义ActionFilter中根据类名字符串做类型转换?

动态实现枚举匹配DTO的JSON转换逻辑

核心实现思路

要完成根据MetricTypes枚举值匹配同名DTO的转换,不需要提前硬编码每一种枚举对应的类型转换逻辑,只需要两步核心操作:

  • 在过滤器初始化阶段,缓存枚举值对应的DTO类型实例,避免运行时反复查找类型的性能损耗
  • 调用Newtonsoft.Json自带的非泛型反序列化重载,传入缓存的Type对象完成转换

关键代码实现

修正后的完整过滤器代码如下:

public class CaptureMetrics : ActionFilterAttribute
{
    private readonly string _metricType;
    private readonly Type _targetDtoType;

    public CaptureMetrics(MetricTypes metricType)
    {
        _metricType = metricType.ToString();
        // 从DTO所在的程序集中,查找和枚举名称完全一致的类作为目标类型
        _targetDtoType = typeof(ApiMetric).Assembly.GetTypes()
            .FirstOrDefault(t => t.Name == _metricType);
        // 启动阶段就校验类型是否存在,避免运行时出错
        if (_targetDtoType == null)
        {
            throw new InvalidOperationException($"未找到与指标类型{_metricType}同名的DTO定义");
        }
    }

    public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        try
        {
            // 开启请求体缓冲,支持流重复读取,不影响后续控制器的模型绑定流程
            context.HttpContext.Request.EnableBuffering();
            var reqPayload = context.HttpContext.Request.Body;
            // 重置流位置到开头,从头读取请求内容
            reqPayload.Position = 0;
            
            string strJson;
            // 读取请求体时设置leaveOpen=true,避免流被提前关闭
            using (var sr = new StreamReader(reqPayload, leaveOpen: true))
            {
                strJson = await sr.ReadToEndAsync();
            }
            // 读完之后再次重置流位置,留给后续模型绑定流程使用
            reqPayload.Position = 0;

            // 带Type参数的非泛型反序列化,直接返回对应DTO类型的实例
            var obj = JsonConvert.DeserializeObject(strJson, _targetDtoType);
            // 后续可直接使用obj做指标采集上报逻辑
        }
        catch (Exception)
        {
            // 补充异常日志记录逻辑
            throw;
        }
        finally
        {
            await next();
        }
    }
}

public enum MetricTypes
{
    ApiMetric
}

// 与枚举同名的DTO定义
public class ApiMetric
{
  // 实体属性定义
}

容易踩的坑说明

  • 不要直接使用Type.GetType(_metricType)查找类型:该方法默认只会在当前执行程序集、系统程序集中搜索类型,直接传入短类名无法定位到项目内的DTO类,会返回null。在构造阶段一次性扫描程序集匹配同名类型,能在应用启动时就发现枚举和DTO不匹配的配置错误,比运行时抛异常更易排查。
  • 必须处理请求流的位置问题:ASP.NET Core的请求体是单向只读流,一旦在过滤器中读取到流末尾,后续控制器的[FromBody]参数绑定会因为读不到流内容返回null。通过EnableBuffering开启请求体缓冲,每次读写完后把流位置重置到开头,就能兼顾过滤器的内容读取和正常的请求处理流程。

内容的提问来源于stack exchange,提问作者Kgn-web

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.07 00:57:00