AutoMapper 6.0+ 必须显式创建 IMapper 实例,静态 Mapper 已废弃;正确方式为手动构建 MapperConfiguration 并调用 CreateMapper(),或通过依赖注入注册 AddAutoMapper();Profile 配置须在构造函数中调用 CreateMap,且需启用 AssertConfigurationIsValid() 验证。

AutoMapper 6.0+ 必须显式创建 IMapper 实例
直接调用 Mapper.Map 会静默失败或抛 System.NullReferenceException——因为静态 Mapper 类在 6.0+ 已被废弃,且默认未初始化。你写的配置再完整,没走 MapperConfiguration.CreateMapper() 就等于没生效。
正确做法只有两条路:
- 手动构建:先 new
MapperConfiguration,调CreateMap,再必须调() config.CreateMapper()得到IMapper实例,之后才能用mapper.Map(src) - 依赖注入(推荐):在
Program.cs(.NET 6+)中调builder.Services.AddAutoMapper(typeof(Startup))或指定 Profile 类型,如AddAutoMapper(typeof(UserProfile));容器会自动提供线程安全的IMapper实例 - 别把
new MapperConfiguration(...)写在 Controller 构造函数里——每次请求都 new 一次,配置重复加载、GC 压力大、还可能因多线程并发导致映射器状态错乱
Profile 配置不生效的典型原因
写了 UserProfile : Profile,也注册了 AddAutoMapper,但 Map() 仍不按预期执行,常见卡点如下:
-
CreateMap没写在() Profile构造函数里,而是放在了某个方法或静态块中——Profile 只扫描构造函数内的CreateMap调用 - 属性名拼写错误或大小写不一致:
ForMember(dest => dest.UserName, ...)不能写成dest => dest.username,C# 属性名严格区分大小写 - 用了
Ignore()却忘了后续需求变更,比如FullName字段某天要返回给前端,但配置里还留着.ForMember(x => x.FullName, opt => opt.Ignore()),结果永远是 null - 没启用配置验证:
config.AssertConfigurationIsValid()应该加在启动时(如 Program.cs 中),它能提前发现类型不兼容、空 MapFrom 表达式、循环引用等隐患,而不是等运行时字段为 null 才去翻日志
MapFrom 访问 null 源属性直接炸掉
MapFrom(src => src.Address.Street) 是高频写法,但一旦 src.Address 为 null,就会抛 NullReferenceException,而 AutoMapper 默认不帮你做空判断。
安全写法有三种:
- 改用
UseValue+ 空判断:.ForMember(dest => dest.Street, opt => opt.UseValue(src.Address?.Street)) - 用
MapFrom包一层空安全表达式:.MapFrom(src => src.Address?.Street ?? string.Empty) - 对整个嵌套路径启用
AllowNullCollections = true(仅限集合)或配置PreserveReferences()(防循环引用),但对单个引用属性无效,必须手动防御
特别注意:不要在 MapFrom 里调用可能抛异常的业务方法(如数据库查询、HTTP 调用),AutoMapper 不处理这类副作用,应提前计算好值再传入。
DTO 与实体映射时的隐性陷阱
看起来只是两个类之间复制字段,但实际容易掉进这些坑:
- 目标类型是
record:旧版 AutoMapper(v11 及以前)不支持无参构造函数的 record,v12+ 支持,但若项目还在用低版本,Map会直接失败,得换回 class 或升级包(obj) - 源/目标字段类型不匹配又没配
ConvertUsing:比如源是DateTime?、目标是string,不声明转换逻辑就静默跳过,字段为 default(string) 即 null - 集合映射误用
Map:如果是在 EF 查询中用,应该用- >(srcList)
ProjectTo做服务端投影,否则先查出全部实体再内存映射,性能崩盘(mapper.ConfigurationProvider) - DataTable / ExpandoObject / Dictionary 这类动态结构:AutoMapper 默认不支持,需额外引入
AutoMapper.Data并调cfg.AddDataReaderMapping(),否则直接报Unmapped members
最麻烦的是“不报错却不对”——AutoMapper 默认静默忽略无法映射的字段,开发阶段务必开 AssertConfigurationIsValid(),上线后也建议加日志记录未映射字段(通过自定义 IValueResolver 或拦截 IMappingAction)。











