AutoMapper在MVC中的运用01-配置、使用、单元测试、举例
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-配置、使用、单元测试、举例的更多相关文章
- AutoMapper在MVC中的运用小结
配置.单元测试.AOP注入 Decimal转换成String类型 源数组转换成目标数组 源中的集合(数组)属性转换成目标中的集合(数组)属性 子类父类间的映射 源字典集合转换成目标字典集合 枚举映射 ...
- 使用ExposedObject对Asp.net MVC中匿名类型的JsonResult做单元测试
返回JsonResult是MVC中的常见返回值类型,而且简单方便的方式是结合匿名类型一起使用. 比如: public ActionResult PreviewEmail() { …… return J ...
- AutoMapper在MVC中的运用07-映射在订单场景的例子
本文参考了Taswar Bhatti的博客,他写了<Instant AutoMapper>这本书.遗憾的是,这本电子版书在国内还买不到,也下载不到.也只能从他的有限几篇博文中来窥探一二了. ...
- AutoMapper在MVC中的运用05-映射中的忽略、处理null、多种映射转换
本篇AutoMapper使用场景: ※ 动态实现接口方法或属性 ※ 目标中的属性如果比源多,可以忽略多出的属性 ※ 目标有virtual属性,可忽略 ※ 目标属性值为null的解决办法 ※ int转s ...
- AutoMapper在MVC中的运用04-string映射各种类型、一个属性映射多个属性等
本篇AutoMapper使用场景: ※ 类型转换,源string类型分别转换成int, DateTime,Type ※ 源和目标都包含复杂类型属性 ※ 把源中的一个属性映射到目标中的多个属性 类型转换 ...
- AutoMapper在MVC中的运用03-字典集合、枚举映射,自定义解析器
本篇AutoMapper使用场景: ※ 源字典集合转换成目标字典集合 ※ 枚举映射 ※ 自定义解析器 ※ 源中的复杂属性和Get...方法转换成目标属性 源字典集合转换成目标字典集合 □ Domain ...
- AutoMapper在MVC中的运用02-Decimal转String、集合、子父类映射
本篇AutoMapper使用场景: ※ Decimal转换成String类型 ※ 源数组转换成目标数组 ※ 源中的集合(数组)属性转换成目标中的集合(数组)属性 ※ 子类父类间的映射 Decimal转 ...
- Spring MVC中 log4j日志文件配置相对路径
log4j和web.xml配置webAppRootKey 的问题 1 在web.xml配置 <context-param> <param-name>webAppRootKey ...
- mvc中hangfire全局简单配置
public void Configuration(IAppBuilder app) { ConfigureAuth(app); //指定使用Sql ...
随机推荐
- Daemon函数的用法
Daemon函数的用法 说明: 让一个程序后台运行. 原型: #include <unistd.h> int daemon(int nochdir, int noclose); #incl ...
- 005_ss-link.info的ping探测工具
用小工具ping.py测试距离您最快的节点 #!/usr/bin/env python # coding: utf-8 """ A pure python ping im ...
- sublime text 3 使用简介
2014年1月22日 09:47:50 2用了一段时间感觉不错,就是自带的高亮显示匹配标签或者代码块儿时有点儿不清楚,所以一直是sublime 开PHP,notepad++开html 现在想只用一个编 ...
- js里size和length的区别
length: length是js的原生方法,用于获取元素的个数和对象的长度 var length = $(obj).length; size(): size()属于方法,只能作用于对象上,获取元素的 ...
- Java编程的逻辑 (56) - 文件概述
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...
- Oracle-查询最近更新的前10条数据
在实际用途中,常常会要求取最近的几条纪录,这就需要先对纪录进行排序后再取rownum <= 一般常见的 SELECT * FROM (SELECT a.* FROM torderdetail a ...
- video.js视频播放器
免费视频播放器videojs中文教程 Video.js是一款web视频播放器,支持html5和flash两种播放方式.更多关于video.js的介绍,可以访问官方网站介绍,我之前也写过一篇关于vide ...
- Zookeeper Canary
ZooKeeper Canary我理解用于测试ZK节点是否正常的心跳服务,这是从ClouderaManager中粘下来的: 这是 ZooKeeper 服务级运行状况测试,用于检查基本客户端操作是否正常 ...
- 025 Spark中的广播变量原理以及测试(共享变量是spark中第二个抽象)
一:来源 1.说明 为啥要有这个广播变量呢. 一些常亮在Driver中定义,然后Task在Executor上执行. 如果,有多个任务在执行,每个任务需要,就会造成浪费. 二:共享变量的官网 1.官网 ...
- 004 jquery过滤选择器-----------(基本过滤选择器)
1.介绍 2.常见基本过滤器 3.程序 <!DOCTYPE html> <html> <head> <meta charset="UTF-8&quo ...