使用 AutoMapper Profiles 的 ASP MVC
IMapper 接口通过 Unity 框架注入到我的类的构造函数中,但您也可以使用任何其他 DI 框架或手动注入 IMapper 接口。
引言
我正在使用 AutoMapper 版本 5.1.1.0,以及 IMapper 接口(与静态类 Mapper 相对)。
IMapper
接口通过 Unity 框架注入到我的类的构造函数中,但您也可以使用任何其他 DI 框架或手动注入 IMapper
接口。
动机
我非常喜欢 AutoMapper 的功能,并且发现它在层之间绑定对象时非常有用。但我确实在让它工作上遇到了一些困难。因此,这应该是一个简单的教程,希望能帮助那些想要从 static Mapper
类迁移到 IMapper
接口的人。或者对于那些以前从未用过 AutoMapper
并且想学习如何配置它的人。因为我找到的大多数教程都不完整或已过时(使用 static Mapper
类)。
单层
如果您只有一个层需要映射模型,我建议不要使用 AutoMapper Profiles,而直接使用简单的解决方案。
public static class MappingProfile { public static MapperConfiguration InitializeAutoMapper() { MapperConfiguration config = new MapperConfiguration(cfg => { cfg.CreateMap<Question, QuestionModel>(); cfg.CreateMap<QuestionModel, Question>(); /*etc...*/ }); return config; } }
这样,您就可以使用所有映射创建 MapperConfiguration
对象。
然后,您可以从该配置创建 IMapper
对象,并将其注入到您的 DI 框架(在我的例子中是 Unity)。
public static class UnityWebActivator { /// <summary>Integrates Unity when the application starts.</summary> public static void Start() { var container = UnityConfig.GetConfiguredContainer(); var mapper = MappingProfile.InitializeAutoMapper().CreateMapper(); container.RegisterInstance<IMapper>(mapper); FilterProviders.Providers.Remove (FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First()); FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container)); DependencyResolver.SetResolver(new UnityDependencyResolver(container)); // TODO: Uncomment if you want to use PerRequestLifetimeManager // Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule // (typeof(UnityPerRequestHttpModule)); } /// <summary>Disposes the Unity container when the application is shut down.</summary> public static void Shutdown() { var container = UnityConfig.GetConfiguredContainer(); container.Dispose(); } }
在第 7 行,创建了 MapperConfiguration
,并通过调用 .CreateMapper()
从该配置获取 IMapper
对象。
在第 8 行,IMapper
接口被 绑定 到此映射器对象(来自第 7 行)。
因此,从现在开始,每当 DI 在构造函数中看到 IMapper
对象时,它将提供此映射器对象(再次是第 7 行)。
现在,举例说明需要 IMapper
的对象
public class BaseService { protected IMapper _mapper; public BaseService(IMapper mapper) { _mapper = mapper; } public void AutoMapperDemo(){ var questions = GetQuestions(token); return _mapper.Map<IEnumerable<Question>, IEnumerable<QuestionModel>>(questions); } public IEnumerable<Question> GetQuestions(token){ /*logic to get Questions*/ } }
这可能是 automapper 的用法。您可以使用 IMapper
接口的 public
方法 Map<>
来映射您的类。IMapper
对象通过 DI 框架或在创建 BaseService
对象时手动注入。
多层
在实际的 MVC 应用程序中,通常会有多个层。您可能拥有类似 WEB/BUSINESS/DB 的层,并且 WEB 不应该了解 DB,因为它只与 BUSINESS 层通信。
这意味着使用单个配置类,您需要在 Web 层引用 DB 项目,否则您无法映射对象。
而 AutoMapper Profiles 正是为此而设计的。
再次使用 MappingProfile 类,现在带有 profiles
public static class MappingProfile { public static MapperConfiguration InitializeAutoMapper() { MapperConfiguration config = new MapperConfiguration(cfg => { cfg.AddProfile(new WebMappingProfile()); //mapping between Web and Business layer objects cfg.AddProfile(new BLProfile()); // mapping between Business and DB layer objects }); return config; } }
//Profile number one saved in Web layer public class WebMappingProfile : Profile { public WebMappingProfile() { CreateMap<Question, QuestionModel>(); CreateMap<QuestionModel, Question>(); /*etc...*/ } } //Profile number two save in Business layer public class BLProfile: Profile { public BLProfile() { CreateMap<BLModels.SubModels.Address, DataAccess.Models.EF.Address>(); /*etc....*/ } }
这样,Web 层就不需要引用 DB 层了。
所有其他步骤与单层相同。
摘要
我认为 AutoMapper 如果使用得当,可以是一个非常有用的工具,但有时很难找到最新的教程。如果您遇到问题,强烈建议您阅读 autommaper wiki。
我鼓励您在评论中分享如何使用例如 Ninject 或 Castle Windsor 配置此功能。