AutoMapper映射DateTime无法转换为正确格式的问题排查
问题:AutoMapper自定义日期转换器未生效的解决方法
问题场景
我有两个API:一个接收POST请求并将数据存入数据库,数据映射至包含Id、DataReceived(多为JSON字符串)、Transfered属性的BaseModel;另一个API负责将DataReceived中的数据通过AutoMapper映射至第二个数据库的ModelOne。
配置的映射规则如下:
CreateMap<JToken, ModelOne>() .ForAllMembers(opt => { opt.MapFrom(src => src.SelectToken(opt.DestinationMember.Name)); opt.Condition((src, des, _, _, resolutionContext) => { MemberInfo propDestination = opt.DestinationMember; string propName = propDestination.Name; // 尝试在这里用类型转换器处理数据 if (Attribute.IsDefined(propDestination, typeof(CustomDateConvertAttribute))) { opt.ConvertUsing(new CustomDateTimeConverter(), src => src.SelectToken(propName).ToString()); } // 所有成员都映射 return true; }); });
自定义转换器实现:
public class CustomDateTimeConverter : IValueConverter<string, string> { public string Convert(string source, ResolutionContext context) { DateTime dt; try { dt = DateTime.Parse(source); } catch (Exception ex) { Console.WriteLine(ex.Message); dt = DateTime.ParseExact(source, "dd/MM/yyyy h:mm:ss tt", CultureInfo.InvariantCulture); } return dt.Year + "-" + dt.Month + "-" + dt.Day + " " + dt.Hour + ":" + dt.Minute + ":" + dt.Second; } }
但日期格式转换并未生效,请问如何解决?
问题原因
在Condition方法内调用opt.ConvertUsing是无效的:
- AutoMapper的配置是初始化阶段一次性完成的,运行时在
Condition中修改映射规则不会被识别; Condition的作用是判断当前成员是否执行映射,而非用来动态添加转换逻辑;- 原写法中
ForAllMembers的逻辑会被每个成员重复执行,配置逻辑混乱。
解决方案
1. 修正映射配置逻辑
将转换器配置从Condition中移出,在配置阶段直接为带有CustomDateConvertAttribute的成员单独设置转换规则:
CreateMap<JToken, ModelOne>() // 为所有成员设置基础映射逻辑 .ForAllMembers(opt => opt.MapFrom(src => src.SelectToken(opt.DestinationMember.Name))) // 针对带自定义属性的成员配置转换器 .ForAllMembers(opt => { if (Attribute.IsDefined(opt.DestinationMember, typeof(CustomDateConvertAttribute))) { opt.ConvertUsing(new CustomDateTimeConverter(), src => src.SelectToken(opt.DestinationMember.Name)?.ToString()); } });
2. 优化转换器实现
原转换器直接拼接字符串会导致格式不规范(如月份/日期小于10时无前置零),改用标准格式字符串输出,同时优化解析逻辑避免捕获通用异常:
public class CustomDateTimeConverter : IValueConverter<string, string> { public string Convert(string source, ResolutionContext context) { if (string.IsNullOrWhiteSpace(source)) { return string.Empty; // 或根据业务返回默认值 } // 先尝试通用解析 if (!DateTime.TryParse(source, out DateTime dt)) { // 失败则尝试指定格式解析 if (!DateTime.TryParseExact(source, "dd/MM/yyyy h:mm:ss tt", CultureInfo.InvariantCulture, DateTimeStyles.None, out dt)) { // 解析失败可抛出异常或返回默认值,根据业务需求调整 throw new FormatException($"无法解析日期字符串:{source}"); } } // 输出标准的yyyy-MM-dd HH:mm:ss格式 return dt.ToString("yyyy-MM-dd HH:mm:ss"); } }
3. 验证属性标记
确保ModelOne中需要转换日期的属性已正确标记CustomDateConvertAttribute:
public class ModelOne { [CustomDateConvert] public string CreateTime { get; set; } // 其他属性... }
关键提示
AutoMapper的配置逻辑必须在初始化阶段完成,运行时动态修改配置不会生效。针对特殊成员的转换规则,应在配置阶段就明确区分,而非在映射执行的判断逻辑中临时添加。
内容的提问来源于stack exchange,提问作者Prosy A.
相关产品推荐
相关产品推荐

