AutoMapper配置须在应用启动时一次性完成并复用,禁止每次映射新建;字段名不一致时需用ForMember显式映射;集合映射需先定义单类型映射;调试首选AssertConfigurationIsValid验证。

AutoMapper配置必须在应用启动时完成,不能每次映射都新建Mapper
AutoMapper不是开箱即用的“调用函数就转换”工具,MapperConfiguration 和 IMapper 实例需要一次性构建并复用。常见错误是写个方法里反复 new MapperConfiguration,这会严重拖慢性能,还可能因类型注册冲突抛出 AutoMapperConfigurationException。
正确做法是在 Program.cs(.NET 6+)或 Startup.cs 中配置:
var mappingConfig = new MapperConfiguration(mc =>
{
mc.AddProfile<MappingProfile>();
});
var mapper = mappingConfig.CreateMapper();
builder.Services.AddSingleton<IMapper>(mapper);
然后通过 DI 注入 IMapper 使用。不手动 new、不静态缓存、不跨请求共享配置对象。
DTO和实体类字段名不一致时,用ForMember显式指定映射规则
AutoMapper默认按名称匹配(case-insensitive),但实际项目中常遇到字段名不一致:比如实体用 CreatedDate,DTO用 CreatedAt;或实体有导航属性 User,DTO只想要 UserId。这时必须用 ForMember 显式声明,否则字段为 null 或映射失败。
示例(在 Profile 子类中):
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<UserEntity, UserDto>()
.ForMember(dest => dest.CreatedAt, opt => opt.MapFrom(src => src.CreatedDate))
.ForMember(dest => dest.UserId, opt => opt.MapFrom(src => src.User.Id));
}
}
- 别漏掉
opt.MapFrom的 lambda 参数,写成src.User?.Id更安全(避免 NullReferenceException) - 如果 DTO 字段是只读属性(如
get;),需额外加.ForCtorParam或启用AllowNullCollections - 不要在
ForMember里调用耗时操作(如 DB 查询),它会在每次映射时执行
集合映射要明确指定泛型类型,List和IEnumerable行为不同
写 mapper.Map<list>>(users)</list> 看似合理,但 AutoMapper 默认不自动展开集合——它需要你先定义 CreateMap<userentity userdto>()</userentity>,再让 AutoMapper 推导 List<userentity> → List<userdto></userdto></userentity>。如果只配了单个类型映射,集合映射会静默失败或返回空列表。
更危险的是混用接口:用 IEnumerable<userdto></userdto> 接收结果时,AutoMapper 返回的是内部包装类型,强制转 List<userdto></userdto> 会报 InvalidCastException。
- 始终优先使用
CreateMap<userentity userdto>()</userentity>+ 直接映射集合变量(mapper.Map<list>>(list)</list>) - 若源是
IQueryable<userentity></userentity>,别直接 map,先.ToList()再映射,否则可能触发 Expression 解析异常 - 大集合慎用 AutoMapper,简单字段拷贝用
foreach + new可能更快,AutoMapper 的反射开销在万级数据下明显
调试映射失败时,先跑Validate(),别靠日志猜
映射结果为 null、字段没值、抛 AutoMapperMappingException,第一反应不该是翻文档,而是调用 configuration.AssertConfigurationIsValid()。它会在启动时检查所有 CreateMap 是否可解析、是否缺失 ForMember、是否有循环引用等。
开发阶段建议加一句:
var config = new MapperConfiguration(c => c.AddProfile<MappingProfile>()); config.AssertConfigurationIsValid(); // 抛异常,立刻暴露问题
常见触发点:
- 实体类有无参构造函数但 DTO 没有(且含只读属性)→ 配置
ConstructUsing - 用了
IncludeBase<a b>()</a>但基类映射未定义 → 先注册基类映射 - DTO 属性是
DateTime?,实体是DateTime,但忘了配置ConvertUsing处理默认值 → 建议统一用可空类型
真实项目里,90% 的“映射不生效”问题,都是配置没生效或 Validate 没跑,而不是语法写错。


















