AutoMapper在MVC中的运用01-配置、使用、单元测试、举例

MVC中,如果想在Domain Model和View Model之间建立映射,用AutoMapper是一个不错的选择。不仅如此,AutoMapper能在不同对象之间建立映射,比如string与int类型, DateTime与int类型,接口与实现类,等等。本篇主要总结AutoMapper在MVC中的配置、使用、单元测试,以及各种映射场景。


注意:

如果通过NuGet下载最新版的AutoMapper,需要注意的是:有些方法,比如ForMember方法,和以前不一样。还有一些方法已经过期。


  配置


□ 全局配置

 

AutoMapper在MVC中的运用01-配置、使用、单元测试、举例
 1 public class MvcApplication : System.Web.HttpApplication

 2 

 3 {

 4 

 5     protected void Application_Start()

 6 

 7     {

 8 

 9         ...

10 

11         ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());

12 

13         CreateMaps();

14 

15     }

16 

17 

18     public void CreateMaps()

19 

20     {

21 

22         AutoMapper.Mapper.Reset();

23 

24         AutoMapper.Mapper.CreateMap<CustomerCreateEditViewModel, Customer>();

25 

26         AutoMapper.Mapper.AssertConfigurationIsValid();

27 

28     }

29 

30 }
View Code

 

这种方法不太利于单元测试。


□ 全局配置 + 静态类配置


AutoMapper静态配置类:


AutoMapper在MVC中的运用01-配置、使用、单元测试、举例
 1     public static class AutoMapperWebConfiguration

 2 

 3     {

 4 

 5         public static void Configure()

 6 

 7         {

 8 

 9             Mapper.Initialize(cfg =>

10 

11             {

12 

13                 cfg.AddProfile(new UserProfile());

14 

15             });

16 

17         }

18 

19     }
View Code

 

UserProfile继承于AutoMapper的Profile类。通过这种继承,我们可以创建不同的映射规则。比如一套规则用于Domain Model转换成View Model,一套规则用于View Model转换成Domain Model。

 

AutoMapper在MVC中的运用01-配置、使用、单元测试、举例
 1     public class UserProfile : Profile

 2 

 3     {

 4 

 5         protected override void Configure()

 6 

 7         {

 8 

 9             AddFormatter<MoneyFormatter>();           

10 

11             Mapper.CreateMap<Order, OrderListViewModel>();

12 

13         }

14 

15     }
View Code

 

最后在全局注册。


AutoMapperWebConfiguration.Configure();


  单元测试


当项目中有比较多的model的时候,通过单元测试,可以发现映射中存在的问题,而不是等到程序运行的时候。


AutoMapper在MVC中的运用01-配置、使用、单元测试、举例
 1     [TestClass]

 2 

 3     public class AutoMapperConfigurationTester

 4 

 5     {

 6 

 7         [TestMethod]

 8 

 9         public void TestMethod1()

10 

11         {

12 

13             AutoMapperWebConfiguration.Configure();

14 

15             Mapper.AssertConfigurationIsValid();

16 

17         }

18 

19     }
View Code

 

  简单例子


□ Domain Models


AutoMapper在MVC中的运用01-配置、使用、单元测试、举例
 1 public class Customer

 2 

 3 {

 4 

 5 public string FirstName{get;set;}

 6 

 7 public string LastName{get;set;}

 8 

 9 public string Email{get;set;}

10 

11 pubic Address HomeAddress{get;set;}

12 

13 public string GetFullName()

14 

15 {

16 

17 return string.Format("{0}{1}", FirstName, LastName);

18 

19 }

20 

21 }

22 

23 

24 public class Address

25 

26 {

27 

28 public string Address1{get;set;}

29 

30 public string Address2{get;set;}

31 

32 public string City{get;set;}

33 

34 public string PostalCode{get;set;}

35 

36 public string Country{get;set;}

37 

38 }
View Code

 

□ View Model


AutoMapper在MVC中的运用01-配置、使用、单元测试、举例
 1 public class CustomerListViewModel

 2 

 3 {

 4 

 5 public string FullName{get;set;}

 6 

 7 public string Email{get;set;}

 8 

 9 public string HomeAddressCountry{get;set;}

10 

11 }
View Code

 

□ Controller


AutoMapper在MVC中的运用01-配置、使用、单元测试、举例
 1 public class CustomersController : Controller

 2 

 3 {

 4 

 5 private readonly ICustomerService m_CustomerService;

 6 

 7 public CustomersController(ICustomerService customerService)

 8 

 9 {

10 

11 m_CustomerService = customerService;

12 

13 }

14 

15 

16 public ActionResult Index()

17 

18 {

19 

20 IList<Customer> customers = m_CustomerService.GetCustomers();

21 

22 //为了演示方便,映射规则没有写在统一的静态类中

23 

24 Mapper.CreateMap<Customer, CustomerListViewModel>();

25 

26 IList<CustomerListViewModel> viewModelList = Mapper.Map<IList<Customer>, IList<CustomerListViewModel>>(customers);

27 

28 return View(viewModelList);

29 

30 }

31 

32 }
View Code

 

□ 要点


AutoMapper的"神奇"是建立在惯例和配置之上的。

○ 目标和源的属性名要尽可能保持一致。

○ 当源的属性是复杂类型时,目标属性如果遵循"源属性+源属性所对应类中的某个字段"的惯例,就像这里的HomeAddressCountry,就能拿到源中复杂类型属性所对应类中的字段。

○ 源中的"Get+其它"形成的方法,在目标中只要把"其它"作为属性名,就可以拿到源中方法的返回值,就像源中的GetFullName()方法,对应目标中的FullName属性。

○ 创建映射永远是类与类间的映射,而通过源获取目标,这里的源可以是单个类,也可以是集合,就像 Mapper.Map<IList<Customer>, IList<CustomerListViewModel>>(customers)。


□ 出处


以上参考了这篇博文:http://bengtbe.com/blog/2009/04/14/using-automapper-to-map-view-models-in-asp-net-mvc/



  把Domain Model与View Model的映射放到系统属性里实现


有时,为了代码更大程度的简洁,我们可以把系统属性里,以Aspect Oriented Programming(AOP),面向切面编程的思想来实现。

通过ActionFilterAttribute过滤系统属性可以控制发生在Action方法之前和之后的事件。

如果Domain Model转换成View Model,那我们就让自定义事件发生在Action方法之后。

如果View Model转换成Domain Model,那我们就让自定义事件发生在Action方法之前。


□ Domain Model转换成View Model


AutoMapper在MVC中的运用01-配置、使用、单元测试、举例
 1     public class DomainToViewAttribute : ActionFilterAttribute

 2 

 3     {

 4 

 5         private readonly Type _destType;

 6 

 7         private readonly Type _sourceType;

 8 

 9 

10         public DomainToViewAttribute(Type sourceType, Type desType)

11 

12         {

13 

14             _sourceType = sourceType;

15 

16             _destType = desType;

17 

18         }

19 

20 

21         public override void OnActionExecuted(ActionExecutedContext filterContext)

22 

23         {

24 

25             var domainModel = filterContext.Controller.ViewData.Model;

26 

27             var viewModel = Mapper.Map(domainModel, _sourceType, _destType);

28 

29             filterContext.Controller.ViewData.Model = viewModel;

30 

31         }

32 

33     }
View Code

 

□ View Model转换成Domain Model


AutoMapper在MVC中的运用01-配置、使用、单元测试、举例
 1     public class ViewToDomainAttribute : ActionFilterAttribute

 2 

 3     {

 4 

 5         private readonly Type _desType;

 6 

 7         private readonly Type _sourseType;

 8 

 9 

10         public ViewToDomainAttribute(Type sourceType, Type desType)

11 

12         {

13 

14             _sourseType = sourceType;

15 

16             _desType = desType;

17 

18         }

19 

20 

21         public override void OnActionExecuting(ActionExecutingContext filterContext)

22 

23         {

24 

25             var viewModel = filterContext.Controller.ViewData.Model;

26 

27             var domainModel = Mapper.Map(viewModel, _sourseType, _desType);

28 

29             filterContext.Controller.ViewData.Model = domainModel;

30 

31         }

32 

33     }
View Code

 

□ 把自定义系统属性打到Action方法之上


    [DomainToView(typeof(IEnumerable<Customer>), typeof(IEnumerable<CustomerInfo>))]

    public ViewResult Index()    



接下来的几篇将介绍AutoMapper的各种使用场景。


你可能感兴趣的:(mapper)