如何在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); } } } }
关键修复点
- 递归遍历:新增
ProcessObject方法,递归处理所有嵌套的复杂类型属性,确保多层嵌套的模型都能被处理。 - 支持可空DateTime:原代码仅处理
typeof(DateTime),新增对DateTime?类型的判断和处理。 - 设置属性值:原代码仅修改了
propValue变量,未调用prop.SetValue(obj, modifiedDate)将修改后的值写回对象,这是原代码不生效的核心问题之一。 - 过滤值类型和字符串:避免递归处理值类型(如int、DateTime本身)的内部属性,提升效率。
内容的提问来源于stack exchange,提问作者R.Garcia
相关产品推荐
相关产品推荐

