You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Action Filter中捕获复杂嵌套模型的所有DateTime字段?

解决Action Filter无法处理嵌套模型中DateTime字段的问题

问题场景

需要实现一个Action Filter来捕获应用中所有DateTime类型字段,但当前Filter仅能处理一级模型的DateTime字段,无法处理嵌套模型(如IngresoOTViewModel包含的IngresoOTPreeliminarViewModel)中的DateTime字段。

相关模型定义:

public class IngresoOTViewModel
{
    public IngresoOTPreeliminarViewModel InfoOT { get; set; }
    // 其他字段已省略
    public string UserNameLog { get; set; }
}

public class IngresoOTPreeliminarViewModel
{
    public int? NumeroOT { get; set; }
    // 其他字段已省略
    public DateTime? HoraLlamado { get; set; }
    public DateTime? HoraLlegada { get; set; }
    public DateTime HoraAtencion { get; set; }
    public DateTime HoraEntrega { get; set; }
    public DateTime? HoraRetiro { get; set; }
    public string Firma { get; set; }
}

原Filter代码(仅支持一级模型):

public class DateTimeCustomActionFilter : Attribute, IActionFilter
{    
    public void OnActionExecuting(ActionExecutingContext context)
    {
        var arguments = context.ActionArguments;
        var dateTimeArguments = arguments.Values;
        foreach (var argument in arguments)
        {
            var type = argument.Value?.GetType();
            if(type is null) continue;
            
            if (type == typeof(DateTime))
            {
                var newValue = Convert.ToDateTime(argument.Value).ModifyDateTime(_userService); 
                context.ActionArguments[argument.Key] = newValue;
                continue;
            }

            IList<PropertyInfo> props = new List<PropertyInfo>(type.GetProperties())
                .Where(p => p.PropertyType == typeof(DateTime)).ToList();
            foreach (var prop in props)
            {
                
                object propValue = prop.GetValue(argument.Value, null);
                object propType = prop.PropertyType;

                var newValue = ((DateTime)propValue).ModifyDateTime(_userService);
                propValue = newValue;
                    
                continue;
                
            }
        }
    }
}

对应的Action方法:

public async Task<IActionResult> IngresarOT([FromBody] IngresoOTViewModel ot, bool calculateActividades = false, int? _faenaId = null)
{
    // 业务逻辑已省略
}

解决方案

核心思路是递归遍历所有嵌套属性,同时修复原代码中未将修改后的值设置回对象的问题,并且支持可空DateTime类型的处理。

修改后的Filter代码:

public class DateTimeCustomActionFilter : Attribute, IActionFilter
{
    private readonly IUserService _userService;

    // 假设通过构造注入获取_userService
    public DateTimeCustomActionFilter(IUserService userService)
    {
        _userService = userService;
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        foreach (var argument in context.ActionArguments)
        {
            var value = argument.Value;
            if (value == null) continue;
            
            // 处理当前参数对象(包括嵌套模型)
            ProcessObject(value);
        }
    }

    private void ProcessObject(object obj)
    {
        if (obj == null) return;
        
        var type = obj.GetType();
        // 跳过值类型和字符串(避免递归值类型的内部属性,如DateTime的Ticks等)
        if (type.IsValueType || type == typeof(string))
        {
            return;
        }

        // 遍历当前对象的所有属性
        foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
        {
            var propValue = prop.GetValue(obj);
            if (propValue == null) continue;

            var propType = prop.PropertyType;
            // 处理非可空DateTime
            if (propType == typeof(DateTime))
            {
                var originalDate = (DateTime)propValue;
                var modifiedDate = originalDate.ModifyDateTime(_userService);
                prop.SetValue(obj, modifiedDate);
            }
            // 处理可空DateTime
            else if (propType == typeof(DateTime?))
            {
                var originalNullableDate = (DateTime?)propValue;
                if (originalNullableDate.HasValue)
                {
                    var modifiedDate = originalNullableDate.Value.ModifyDateTime(_userService);
                    prop.SetValue(obj, modifiedDate);
                }
            }
            // 处理嵌套的复杂类型(递归调用)
            else if (!propType.IsValueType && propType != typeof(string))
            {
                ProcessObject(propValue);
            }
        }
    }
}

关键修复点

  1. 递归遍历:新增ProcessObject方法,递归处理所有嵌套的复杂类型属性,确保多层嵌套的模型都能被处理。
  2. 支持可空DateTime:原代码仅处理typeof(DateTime),新增对DateTime?类型的判断和处理。
  3. 设置属性值:原代码仅修改了propValue变量,未调用prop.SetValue(obj, modifiedDate)将修改后的值写回对象,这是原代码不生效的核心问题之一。
  4. 过滤值类型和字符串:避免递归处理值类型(如int、DateTime本身)的内部属性,提升效率。

内容的提问来源于stack exchange,提问作者R.Garcia

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 12:15:32