分层架构中正确使用AutoMapper的方法及初始化位置咨询
分层架构中AutoMapper的正确使用与初始化问题
根据你的分层架构(DTO、Models、ViewModels分属不同层级),需要实现DAL→BLL→控制台PL的双向映射,但出现AutoMapper.AutoMapperMappingException: 'Missing type map configuration or unsupported mapping'错误。当前ViewModel→DTO映射正常,但BLL中DTO→Model的映射失败。
当前代码示例
UI层UiBookService代码
private IMapper _mapper; private readonly BLL.BookService _bookService; public UiBookService(UserDTO currentUser) { _mapper = new MapperConfiguration(cfg => cfg.CreateMap<BookViewModel, BookDTO>()).CreateMapper(); _bookService = new BLL.BookService(currentUser); CurrentUser = currentUser; }
UI层映射使用代码
await _bookService.CreateBook(_mapper.Map<BookDTO>(book));
BLL层BookService出错代码
public async Task CreateBook(BookDTO book) { book.OwnerId = _currentUser.Id; await _bookRepo.CreateAsync(_mapper.Map<Book>(book)); }
核心问题分析
你当前的实现错误在于每个服务都单独初始化局部的Mapper实例,且BLL层的BookService中要么未正确配置BookDTO→Book的映射规则,要么_mapper实例根本未完成初始化(代码中未展示BLL层_mapper的初始化逻辑)。
正确的初始化与使用方式
在分层架构中,AutoMapper的映射配置应集中初始化,而非在每个服务中零散创建,同时要根据分层依赖关系合理拆分配置:
分层拆分映射规则
- DAL/BLL层:负责配置
Model↔DTO的映射(可放在BLL层或单独的映射配置类库中,避免层间强依赖) - UI层:负责配置
ViewModel↔DTO的映射
- DAL/BLL层:负责配置
全局集中初始化Mapper
在应用启动时(比如控制台程序的Main方法),集中创建MapperConfiguration并生成全局IMapper实例,通过依赖注入(DI)注入到各个服务中,而非在服务内部手动创建:// 集中配置所有映射规则 var config = new MapperConfiguration(cfg => { // BLL/DAL层映射:BookDTO ↔ Book cfg.CreateMap<BookDTO, Book>(); cfg.CreateMap<Book, BookDTO>(); // UI层映射:BookViewModel ↔ BookDTO cfg.CreateMap<BookViewModel, BookDTO>(); cfg.CreateMap<BookDTO, BookViewModel>(); }); // 开发环境开启,提前验证配置正确性 config.AssertConfigurationIsValid(); // 创建全局Mapper实例 var mapper = config.CreateMapper(); // 依赖注入注册(以Microsoft.Extensions.DependencyInjection为例) var services = new ServiceCollection(); services.AddSingleton<IMapper>(mapper); services.AddScoped<BLL.BookService>(); services.AddScoped<UiBookService>(); // 注册其他服务与仓储修改服务代码,通过DI注入IMapper
UI层
UiBookService修改:private readonly IMapper _mapper; private readonly BLL.BookService _bookService; // 构造函数注入IMapper与BookService public UiBookService(UserDTO currentUser, IMapper mapper, BLL.BookService bookService) { _mapper = mapper; _bookService = bookService; CurrentUser = currentUser; }BLL层
BookService修改:private readonly IMapper _mapper; private readonly IBookRepo _bookRepo; private readonly UserDTO _currentUser; // 构造函数注入IMapper与仓储 public BookService(UserDTO currentUser, IMapper mapper, IBookRepo bookRepo) { _currentUser = currentUser; _mapper = mapper; _bookRepo = bookRepo; } public async Task CreateBook(BookDTO book) { book.OwnerId = _currentUser.Id; await _bookRepo.CreateAsync(_mapper.Map<Book>(book)); }
关键注意点
- 避免在每个服务中单独创建
MapperConfiguration,重复创建会造成性能损耗,且易遗漏映射规则 - 开发环境启用
AssertConfigurationIsValid(),可提前发现未配置的映射字段或错误 - 若分层依赖严格(比如UI层不能直接引用DAL的Model),可将映射配置拆分到对应层级的
Profile类中,启动时合并加载:// BLL层Profile public class BookProfile : Profile { public BookProfile() { CreateMap<BookDTO, Book>(); CreateMap<Book, BookDTO>(); } } // UI层Profile public class BookViewModelProfile : Profile { public BookViewModelProfile() { CreateMap<BookViewModel, BookDTO>(); CreateMap<BookDTO, BookViewModel>(); } } // 启动时加载所有Profile var config = new MapperConfiguration(cfg => { cfg.AddProfile<BookProfile>(); cfg.AddProfile<BookViewModelProfile>(); });
内容的提问来源于stack exchange,提问作者kirill_divine
相关产品推荐
相关产品推荐

