zoukankan      html  css  js  c++  java
  • AutoMapper在MVC中的运用01-配置、使用、单元测试、举例

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


    注意:

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


      配置


    □ 全局配置

     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静态配置类:


     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。

     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的时候,通过单元测试,可以发现映射中存在的问题,而不是等到程序运行的时候。


     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


     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


     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


     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


     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


     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的各种使用场景。


  • 相关阅读:
    ABP 番外篇-容器
    ABP 番外篇-菜单
    三、写服务
    十二、异步
    一、PHP_OSS使用
    十一、泛型
    Automapper
    ABP实践学习
    【2019-07-26】省是缺点
    【2019-07-25】女人,很强大
  • 原文地址:https://www.cnblogs.com/darrenji/p/3570474.html
Copyright © 2011-2022 走看看