ASP.NET MVC运行方法时出现AutoMapper类型映射配置缺失或不支持映射错误
从你贴的代码来看,这个错误大概率是AutoMapper的映射配置没有被正确加载,或者配置本身存在隐性问题。我之前在ASP.NET MVC项目里也碰到过类似情况,给你几个排查和解决的方向:
1. 优先检查AutoMapper初始化的顺序
你的ConfigureAutoMapper()是在Application_Start里调用的,但看代码顺序,你先启动了StructureMap IoC容器,才初始化AutoMapper。这会导致一个问题:如果IoC容器提前创建了依赖AutoMapper的服务实例,此时映射还没配置好,就会抛出缺失映射的错误。
解决办法:调整Application_Start的调用顺序,把AutoMapper初始化移到IoC容器启动之前:
void Application_Start(object sender, EventArgs e) { // 应用启动时运行的代码 AreaRegistration.RegisterAllAreas(); AutoMapConfig.ConfigureAutoMapper(); // 先初始化AutoMapper,确保映射先加载 StructuremapMvc.Start(); // 再启动IoC容器 GlobalConfiguration.Configure(WebApiConfig.Register); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); }
2. 补全缺失的双向映射
我注意到你的配置里只写了cfg.CreateMap<AspNetUsers, AspNetUsersView>(),没有反向的cfg.CreateMap<AspNetUsersView, AspNetUsers>()。如果OrderView里包含AspNetUsersView类型的属性,AutoMapper找不到这个子类型的映射,就会抛出整体的缺失映射错误。
解决办法:在映射配置中补上这个双向映射:
cfg.CreateMap<AspNetUsersView, AspNetUsers>();
3. 用更严谨的方式配置AutoMapper(推荐)
如果你用的是AutoMapper 8.0以上的版本,旧的静态Mapper.Initialize方式容易出现静态上下文的问题,推荐使用MapperConfiguration的方式,还能提前验证配置是否正确:
修改你的AutoMapConfig类:
public static class AutoMapConfig { public static void ConfigureAutoMapper() { var config = new MapperConfiguration(cfg => { // 保留你所有的映射配置,补上AspNetUsersView到AspNetUsers的映射 cfg.CreateMap<Product, ProductView>() .ForMember(vm => vm.ProductRating, m => m.MapFrom(u => u.ProductReviews != null && u.ProductReviews.Count > 0 ? (Convert.ToInt32(Math.Round(u.ProductReviews.Average(x => x.Rating), 0))) : 0)); cfg.CreateMap<ProductView, Product>(); cfg.CreateMap<Cart, CartView>(); cfg.CreateMap<Category, CategoryView>(); cfg.CreateMap<CategoryView, Category>(); cfg.CreateMap<AspNetUsers, AspNetUsersView>(); cfg.CreateMap<AspNetUsersView, AspNetUsers>(); // 补上这个双向映射 cfg.CreateMap<ProductReview, ProductReviewView>().ForMember(vm => vm.ReviewOwner, m => m.MapFrom(u => u.AspNetUsers.UserName)); cfg.CreateMap<ProductReviewView, ProductReview>(); cfg.CreateMap<Cart, CartView>(); cfg.CreateMap<Order, OrderView>(); cfg.CreateMap<OrderView, Order>().ForMember(x => x.OrderDetails, opt => opt.Ignore()); cfg.CreateMap<OrderDetail, OrderDetailView>(); cfg.CreateMap<OrderStatus, OrderStatusView>(); }); // 这一步很重要!启动时就验证所有映射配置,有问题直接抛出错误,方便排查 config.AssertConfigurationIsValid(); // 给静态Mapper实例赋值 Mapper.Instance = config.CreateMapper(); } }
这样修改后,只要配置有问题(比如缺子类型映射),项目启动时就会抛出异常,直接告诉你哪里错了,不用等到运行时才发现。
4. 临时调试:确认映射是否已注册
如果还是不确定,可以在出错的代码前加一行调试代码,检查映射是否真的被加载了:
using (var onlineShopContext = new OnlineShopWebEntities()) { // 调试用:检查OrderView到Order的映射是否存在 bool hasMapping = Mapper.Configuration.HasMapFor<OrderView, Order>(); // 如果hasMapping是false,说明映射确实没加载,回到第一步调整初始化顺序 Order newOrder = AutoMapper.Mapper.Map<OrderView, Order>(order); // ... 剩下的代码 }
内容的提问来源于stack exchange,提问作者Owais

