ASP.NET项目中AutoMapper V6.1.1多映射用Mapper.Initialize报错的解决咨询
你遇到的这个问题其实是AutoMapper 6.x版本中静态Mapper的一个常见坑——静态Mapper的Initialize方法全局只能调用一次,多次调用会覆盖之前的所有配置。
你之前用MapperConfiguration创建局部配置的方式,每个配置都是独立的,不会互相影响;但切换到静态的Mapper.Initialize()后,如果你的代码里有其他地方也调用了Mapper.Initialize()(哪怕是在另一个模块里),后面的调用会完全覆盖之前的映射配置,导致你第一次配置的A->B映射被清空,运行时自然就报找不到映射的错误了。而单个映射时没问题,是因为那次初始化没有被其他初始化操作覆盖。
修复方案
1. 确保Mapper.Initialize()全局只执行一次
把所有的映射配置集中到应用启动的入口处执行,比如ASP.NET项目的Global.asax的Application_Start方法里:
protected void Application_Start() { // 全局唯一的初始化调用,把所有映射都放在这里 Mapper.Initialize(cfg => { cfg.CreateMap<A, B>(); cfg.CreateMap<C, D>().ForMember(dest => dest.CityDesc, opt => opt.MapFrom(src => src.City)); }); // 其他应用启动配置,比如路由、依赖注入等... }
之后在业务代码里直接使用静态Mapper即可,不要在其他地方再调用Mapper.Initialize()。
2. 用Profile拆分配置(可选,更易维护)
如果你的映射配置很多,可以把不同模块的映射拆分成独立的Profile类,然后在初始化时统一添加,这样既清晰又避免配置混乱:
// 定义Profile类 public class ABMappingProfile : Profile { public ABMappingProfile() { CreateMap<A, B>(); } } public class CDMappingProfile : Profile { public CDMappingProfile() { CreateMap<C, D>().ForMember(dest => dest.CityDesc, opt => opt.MapFrom(src => src.City)); } } // 在Application_Start里初始化 protected void Application_Start() { Mapper.Initialize(cfg => { cfg.AddProfile<ABMappingProfile>(); cfg.AddProfile<CDMappingProfile>(); }); }
3. 优先使用实例化Mapper(更推荐的最佳实践)
其实从AutoMapper 5.x之后,官方就更推荐使用实例化的Mapper而非静态Mapper,因为静态Mapper容易因为初始化时机问题导致配置丢失,也不利于单元测试。如果可以的话,你可以回到类似原来的写法,但把配置注册到依赖注入容器里(ASP.NET可以用第三方DI框架或者自己管理):
// 应用启动时创建配置并注册实例 var config = new MapperConfiguration(cfg => { cfg.CreateMap<A, B>(); cfg.CreateMap<C, D>().ForMember(dest => dest.CityDesc, opt => opt.MapFrom(src => src.City)); }); // 验证配置是否正确(可选,但能提前发现错误) config.AssertConfigurationIsValid(); // 把IMapper注册到DI容器,或者保存为全局实例 var mapper = config.CreateMapper();
之后在需要映射的地方注入IMapper或者直接使用这个全局实例,这样就不会有静态Mapper的初始化覆盖问题了。
内容的提问来源于stack exchange,提问作者Elnaz

