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

注意:

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

配置

□ 全局配置

 public class MvcApplication : System.Web.HttpApplication

 {

     protected void Application_Start()

     {

         ...

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

         CreateMaps();

     }

     public void CreateMaps()

     {

         AutoMapper.Mapper.Reset();

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

         AutoMapper.Mapper.AssertConfigurationIsValid();

     }

 }

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

□ 全局配置 + 静态类配置

AutoMapper静态配置类:

     public static class AutoMapperWebConfiguration

     {

         public static void Configure()

         {

             Mapper.Initialize(cfg =>

             {

                 cfg.AddProfile(new UserProfile());

             });

         }

     }

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

     public class UserProfile : Profile

     {

         protected override void Configure()

         {

             AddFormatter<MoneyFormatter>();           

             Mapper.CreateMap<Order, OrderListViewModel>();

         }

     }

最后在全局注册。

AutoMapperWebConfiguration.Configure();

单元测试

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

     [TestClass]

     public class AutoMapperConfigurationTester

     {

         [TestMethod]

         public void TestMethod1()

         {

             AutoMapperWebConfiguration.Configure();

             Mapper.AssertConfigurationIsValid();

         }

     }

简单例子

□ Domain Models

 public class Customer

 {

 public string FirstName{get;set;}

 public string LastName{get;set;}

 public string Email{get;set;}

 pubic Address HomeAddress{get;set;}

 public string GetFullName()

 {

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

 }

 }

 public class Address

 {

 public string Address1{get;set;}

 public string Address2{get;set;}

 public string City{get;set;}

 public string PostalCode{get;set;}

 public string Country{get;set;}

 }

□ View Model

 public class CustomerListViewModel

 {

 public string FullName{get;set;}

 public string Email{get;set;}

 public string HomeAddressCountry{get;set;}

 }

□ Controller

 public class CustomersController : Controller

 {

 private readonly ICustomerService m_CustomerService;

 public CustomersController(ICustomerService customerService)

 {

 m_CustomerService = customerService;

 }

 public ActionResult Index()

 {

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

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

 Mapper.CreateMap<Customer, CustomerListViewModel>();

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

 return View(viewModelList);

 }

 }

□ 要点

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

     public class DomainToViewAttribute : ActionFilterAttribute

     {

         private readonly Type _destType;

         private readonly Type _sourceType;

         public DomainToViewAttribute(Type sourceType, Type desType)

         {

             _sourceType = sourceType;

             _destType = desType;

         }

         public override void OnActionExecuted(ActionExecutedContext filterContext)

         {

             var domainModel = filterContext.Controller.ViewData.Model;

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

             filterContext.Controller.ViewData.Model = viewModel;

         }

     }

□ View Model转换成Domain Model

     public class ViewToDomainAttribute : ActionFilterAttribute

     {

         private readonly Type _desType;

         private readonly Type _sourseType;

         public ViewToDomainAttribute(Type sourceType, Type desType)

         {

             _sourseType = sourceType;

             _desType = desType;

         }

         public override void OnActionExecuting(ActionExecutingContext filterContext)

         {

             var viewModel = filterContext.Controller.ViewData.Model;

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

             filterContext.Controller.ViewData.Model = domainModel;

         }

     }

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

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

public ViewResult Index()

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

AutoMapper在MVC中的运用01-配置、使用、单元测试、举例的更多相关文章

  1. AutoMapper在MVC中的运用小结

    配置.单元测试.AOP注入 Decimal转换成String类型 源数组转换成目标数组 源中的集合(数组)属性转换成目标中的集合(数组)属性 子类父类间的映射 源字典集合转换成目标字典集合 枚举映射 ...

  2. 使用ExposedObject对Asp.net MVC中匿名类型的JsonResult做单元测试

    返回JsonResult是MVC中的常见返回值类型,而且简单方便的方式是结合匿名类型一起使用. 比如: public ActionResult PreviewEmail() { …… return J ...

  3. AutoMapper在MVC中的运用07-映射在订单场景的例子

    本文参考了Taswar Bhatti的博客,他写了<Instant AutoMapper>这本书.遗憾的是,这本电子版书在国内还买不到,也下载不到.也只能从他的有限几篇博文中来窥探一二了. ...

  4. AutoMapper在MVC中的运用05-映射中的忽略、处理null、多种映射转换

    本篇AutoMapper使用场景: ※ 动态实现接口方法或属性 ※ 目标中的属性如果比源多,可以忽略多出的属性 ※ 目标有virtual属性,可忽略 ※ 目标属性值为null的解决办法 ※ int转s ...

  5. AutoMapper在MVC中的运用04-string映射各种类型、一个属性映射多个属性等

    本篇AutoMapper使用场景: ※ 类型转换,源string类型分别转换成int, DateTime,Type ※ 源和目标都包含复杂类型属性 ※ 把源中的一个属性映射到目标中的多个属性 类型转换 ...

  6. AutoMapper在MVC中的运用03-字典集合、枚举映射,自定义解析器

    本篇AutoMapper使用场景: ※ 源字典集合转换成目标字典集合 ※ 枚举映射 ※ 自定义解析器 ※ 源中的复杂属性和Get...方法转换成目标属性 源字典集合转换成目标字典集合 □ Domain ...

  7. AutoMapper在MVC中的运用02-Decimal转String、集合、子父类映射

    本篇AutoMapper使用场景: ※ Decimal转换成String类型 ※ 源数组转换成目标数组 ※ 源中的集合(数组)属性转换成目标中的集合(数组)属性 ※ 子类父类间的映射 Decimal转 ...

  8. Spring MVC中 log4j日志文件配置相对路径

    log4j和web.xml配置webAppRootKey 的问题 1 在web.xml配置 <context-param>  <param-name>webAppRootKey ...

  9. mvc中hangfire全局简单配置

    public void Configuration(IAppBuilder app)       {           ConfigureAuth(app);           //指定使用Sql ...

随机推荐

  1. Promise初探

    在JavaScript的世界中,所有代码都是单线程执行的. 由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行.异步执行可以用回调函数实现: function ru ...

  2. 说commit,rollback

    事务执行失败后,看做的是commit还是rollback:commit是把执行成功的部分提交了,rollback就是全回滚了.如果rollback失败了,此时不处理,等到客户端断开,MySQL内部默认 ...

  3. cos,sina,tan,cot

    这些都是三角形的公式. 三角形总之就是一个直角两个锐角. cos就是余弦定理,就是锐角的邻边除以三角形的斜边. sin就是正弦定理,就是锐角的对边除以三角形的斜边. tan就是正切定理,就是锐角的对边 ...

  4. H5地理位置定位

    一:介绍使用的知识点 1.地理定位的原理 2.geolocation对象 3.Geolocation Api 4.getCurrentPosition的第一个参数 5.getCurrentPositi ...

  5. 本机Tomcat启动myeclipse,用Jmeter录制脚本端口冲突解决办法

    今天用jmeter 录制脚本与已经启动的Tomcat端口冲突,无法启动工作台的http代理服务器, 如果两个的端口一样,则http代理服务器启动就会提示端口被占用 所以先把Tomcat端口和http代 ...

  6. 007.Zabbix监控图形绘制

    一 Graphs配置 1.1 新建图形 Graphs是将数据展示为图像,以视觉化形式展示,Graphs的配置保存在主机和模板中. Configuration---->Hosts---->G ...

  7. AngularJs指令配置参数scope详解

    AngularJs最重要也是最难理解的模块之一就是它的指令(directive)了,自定义指令配置有很多个参数,下面我只说说其中scope的配置极其含义. scope表示指令的作用域,它有三个可选值: ...

  8. linux 驱动之LCD驱动(有framebuffer)

    <简介> LCD驱动里有个很重要的概念叫帧缓冲(framebuffer),它是Linux系统为显示设备提供的一个接口,应用程序在图形模式允许对显示缓冲区进行读写操作.用户根本不用关心物理显 ...

  9. android 进程间通信 messenger 是什么 binder 跟 aidl 区别 intent 进程间 通讯? android 消息机制 进程间 android 进程间 可以用 handler么 messenger 与 handler 机制 messenger 机制 是不是 就是 handler 机制 或 , 是不是就是 消息机制 android messenge

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha messenger 是什么 binder 跟 aidl 区别 intent 进程间 通讯 ...

  10. [USACO06JAN]Redundant Paths

    OJ题号:洛谷2860.POJ3177 题目大意: 给定一个无向图,试添加最少的边使得原图中没有桥. 思路: Tarjan缩点,然后统计度为$1$的连通分量的个数(找出原图中所有的桥). 考虑给它们每 ...