AutoMapper 10.0使用教程
什么是AutoMapper
我们都知道,引用类型直接赋值传递的是地址,如果直接赋值,则改变一个类的属性的同时也在改变另一个类。
所以,当我们需要实现像int类型直接赋值更改互不影响的效果时,我们需要映射。
将A类映射赋值到B类的时候,我们就需要一个对象映射器(object-object),也就是AutoMapper。
我们只需要提前配置好要映射的两个类,即可轻松实现反射。
配置
使用MapperConfiguration配置
创建一个 MapperConfiguration
实例并通过构造函数初始化配置:
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<Foo, Bar>();
cfg.AddProfile<FooProfile>();
});
MapperConfiguration
实例可以静态存储,也可以存储在静态字段或依赖注入容器中。一旦创建,它就不能被更改/修改。
var configuration = new MapperConfiguration(cfg => {
cfg.CreateMap<Foo, Bar>();
cfg.AddProfile<FooProfile>();
});
注:从9.0开始,静态 API 不再可用。
使用Profile Instances配置
组织映射配置的一个好方法是使用配置文件。创建从 Profile 继承的类,并将配置放入构造函数中:
// This is the approach starting with version 5
public class OrganizationProfile : Profile
{
public OrganizationProfile()
{
CreateMap<Foo, FooDto>();
// Use CreateMap... Etc.. here (Profile methods are the same as configuration methods)
}
}
// How it was done in 4.x - as of 5.0 this is obsolete:
// public class OrganizationProfile : Profile
// {
// protected override void Configure()
// {
// CreateMap<Foo, FooDto>();
// }
// }
在早期版本中,使用 Configure
方法而不是构造函数。从版本5开始,Configure ()
就过时了。它将在6.0版本中被删除。
配置文件中的配置只应用于配置文件中的映射。应用于根配置的配置应用于创建的所有映射。
Assembly Scanning for auto configuration (自动配置程序集扫描)
配置文件可以通过多种方式直接添加到主映射器配置中:
cfg.AddProfile<OrganizationProfile>();
cfg.AddProfile(new OrganizationProfile());
or by automatically scanning for profiles:
或者通过自动扫描档案:
// Scan for all profiles in an assembly
// ... using instance approach:
var config = new MapperConfiguration(cfg => {
cfg.AddMaps(myAssembly);
});
var configuration = new MapperConfiguration(cfg => cfg.AddMaps(myAssembly));
// Can also use assembly names:
var configuration = new MapperConfiguration(cfg =>
cfg.AddMaps(new [] {
"Foo.UI",
"Foo.Core"
});
);
// Or marker types for assemblies:
var configuration = new MapperConfiguration(cfg =>
cfg.AddMaps(new [] {
typeof(HomeController),
typeof(Entity)
});
);
AutoMapper 将扫描指定的程序集,从 Profile
继承类,并将它们添加到配置中。
Naming Conventions(命名约定)
您可以设置源和目标命名约定
var configuration = new MapperConfiguration(cfg => {
cfg.SourceMemberNamingConvention = new LowerUnderscoreNamingConvention();
cfg.DestinationMemberNamingConvention = new PascalCaseNamingConvention();
});
这将把以下属性映射到彼此: property _ name-> PropertyName
您还可以将其设置为每个配置文件级别
public class OrganizationProfile : Profile
{
public OrganizationProfile()
{
SourceMemberNamingConvention = new LowerUnderscoreNamingConvention();
DestinationMemberNamingConvention = new PascalCaseNamingConvention();
//Put your CreateMap... Etc.. here
}
}
如果你不需要变数命名原则,你可以使用精确匹配命名协议。
Replacing characters (替换字符)
还可以在成员名称匹配过程中替换源成员中的单个字符或整个单词:
public class Source
{
public int Value { get; set; }
public int Ävíator { get; set; }
public int SubAirlinaFlight { get; set; }
}
public class Destination
{
public int Value { get; set; }
public int Aviator { get; set; }
public int SubAirlineFlight { get; set; }
}
We want to replace the individual characters, and perhaps translate a word:
我们想要替换单个字符,或许可以翻译一个单词:
var configuration = new MapperConfiguration(c =>
{
c.ReplaceMemberName("Ä", "A");
c.ReplaceMemberName("í", "i");
c.ReplaceMemberName("Airlina", "Airline");
});
Recognizing pre/postfixes 识别前/后缀
有时候,源/目标属性会有共同的前/后缀,这导致您必须执行一系列自定义成员映射,因为名称不匹配。为了解决这个问题,您可以识别前/后缀:
public class Source {
public int frmValue { get; set; }
public int frmValue2 { get; set; }
}
public class Dest {
public int Value { get; set; }
public int Value2 { get; set; }
}
var configuration = new MapperConfiguration(cfg => {
cfg.RecognizePrefixes("frm");
cfg.CreateMap<Source, Dest>();
});
默认情况下,AutoMapper 识别前缀“ Get” ,如果您需要清除前缀:
var configuration = new MapperConfiguration(cfg => {
cfg.ClearPrefixes();
cfg.RecognizePrefixes("tmp");
});
Global property/field filtering 全局属性/字段筛选
默认情况下,AutoMapper 会尝试映射每个公共属性/字段。您可以使用属性/字段过滤器过滤出属性/字段:
var configuration = new MapperConfiguration(cfg =>
{
// don't map any fields
cfg.ShouldMapField = fi => false;
// map properties with a public or private getter
cfg.ShouldMapProperty = pi =>
pi.GetMethod != null && (pi.GetMethod.IsPublic || pi.GetMethod.IsPrivate);
});
Configuring
Visibility 配置可见性
默认情况下,AutoMapper 只能识别公共成员。它可以映射到私有 setters
,但是如果整个属性都是 private/internal
,则会跳过 internal/private
方法和属性。要指示 AutoMapper 识别具有其他可视性的成员,请覆盖默认过滤器 ShouldMapField
和/或 shouldmapproty
:
var configuration = new MapperConfiguration(cfg =>
{
// map properties with public or internal getters
cfg.ShouldMapProperty = p => p.GetMethod.IsPublic || p.GetMethod.IsAssembly;
cfg.CreateMap<Source, Destination>();
});
Configuration compilation 配置编译
由于表达式编译可能占用位资源,因此 AutoMapper 在第一个映射上编译类型映射计划。然而,这种行为并不总是可取的,所以你可以告诉 AutoMapper 直接编译它的映射:
var configuration = new MapperConfiguration(cfg => {});
configuration.CompileMappings();
对于几百个映射,这可能需要几秒钟。
Dependency Injection (依赖注入)
AutoMapper 支持使用静态服务位置构建自定义值解析器、自定义类型转换器和值转换器:
var configuration = new MapperConfiguration(cfg =>
{
cfg.ConstructServicesUsing(ObjectFactory.GetInstance);
cfg.CreateMap<Source, Destination>();
});
或动态服务位置,用于基于实例的容器(包括子/嵌套容器) :
var mapper = new Mapper(configuration, childContainer.GetInstance);
var dest = mapper.Map<Source, Destination>(new Source { Value = 15 });
Queryable Extensions 可查询扩展
从8.0开始,你可以使用 IMapper。ProjectTo.对于旧版本,您需要将配置传递给扩展方法 IQueryable。项目组 < t > (图像提供者)。
注意 IQueryable。ProjectTo
是比IMappe更有限 的映射,因为只支持基础 LINQ 提供程序所允许的内容。这意味着不能像对 Map 那样对值解析器和转换器使用 DI。
例子
ASP.NET Core
有一个 NuGet 包将与这里描述的默认注入机制一起使用,并在这个项目中使用。
您可以使用配置文件定义配置。然后你让 AutoMapper 知道哪些程序集是通过在启动时调用 IServiceCollection 扩展方法 AddAutoMapper 定义的概要文件:
services.AddAutoMapper(profileAssembly1, profileAssembly2 /*, ...*/);
or marker types:
或者标记类型:
services.AddAutoMapper(typeof(ProfileTypeFromAssembly1), typeof(ProfileTypeFromAssembly2) /*, ...*/);
现在你可以在运行时将 AutoMapper 注入到你的服务/控制器中:
public class EmployeesController {
private readonly IMapper _mapper;
public EmployeesController(IMapper mapper) => _mapper = mapper;
// use _mapper.Map or _mapper.ProjectTo
}
AutoFac
Ninject
对于那些使用 Ninject 的人来说,这里是一个用于 AutoMapper 的 Ninject 模块的例子
public class AutoMapperModule : NinjectModule
{
public override void Load()
{
Bind<IValueResolver<SourceEntity, DestModel, bool>>().To<MyResolver>();
var mapperConfiguration = CreateConfiguration();
Bind<MapperConfiguration>().ToConstant(mapperConfiguration).InSingletonScope();
// This teaches Ninject how to create automapper instances say if for instance
// MyResolver has a constructor with a parameter that needs to be injected
Bind<IMapper>().ToMethod(ctx =>
new Mapper(mapperConfiguration, type => ctx.Kernel.Get(type)));
}
private MapperConfiguration CreateConfiguration()
{
var config = new MapperConfiguration(cfg =>
{
// Add all profiles in current assembly
cfg.AddMaps(GetType().Assembly);
});
return config;
}
}
Simple Injector 简单注射器
工作流程如下:
- 通过 myregistry.Register 注册你的类型
MapperProvider
允许您直接将IMapper
实例注入到其他类中- 使用
propertythatdependensoniovalueresolver
解析一个值 - 将 IService 注入到
propertythatdependensoniovalueresolver
中,然后就可以使用了
ValueResolver 可以访问 IService,因为我们通过 MapperConfigurationExpression. ConstructServicesUsing 注册容器
public class MyRegistrar
{
public void Register(Container container)
{
// Injectable service
container.RegisterSingleton<IService, SomeService>();
// Automapper
container.RegisterSingleton(() => GetMapper(container));
}
private AutoMapper.IMapper GetMapper(Container container)
{
var mp = container.GetInstance<MapperProvider>();
return mp.GetMapper();
}
}
public class MapperProvider
{
private readonly Container _container;
public MapperProvider(Container container)
{
_container = container;
}
public IMapper GetMapper()
{
var mce = new MapperConfigurationExpression();
mce.ConstructServicesUsing(_container.GetInstance);
mce.AddMaps(typeof(SomeProfile).Assembly);
var mc = new MapperConfiguration(mce);
mc.AssertConfigurationIsValid();
IMapper m = new Mapper(mc, t => _container.GetInstance(t));
return m;
}
}
public class SomeProfile : Profile
{
public SomeProfile()
{
var map = CreateMap<MySourceType, MyDestinationType>();
map.ForMember(d => d.PropertyThatDependsOnIoc, opt => opt.MapFrom<PropertyThatDependsOnIocValueResolver>());
}
}
public class PropertyThatDependsOnIocValueResolver : IValueResolver<MySourceType, object, int>
{
private readonly IService _service;
public PropertyThatDependsOnIocValueResolver(IService service)
{
_service = service;
}
int IValueResolver<MySourceType, object, int>.Resolve(MySourceType source, object destination, int destMember, ResolutionContext context)
{
return _service.MyMethod(source);
}
}
Castle Windsor
对于那些使用Castle Windsor在这里是一个例子
public class AutoMapperInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
// Register all mapper profiles
container.Register(
Classes.FromAssemblyInThisApplication(GetType().Assembly)
.BasedOn<Profile>().WithServiceBase());
// Register IConfigurationProvider with all registered profiles
container.Register(Component.For<IConfigurationProvider>().UsingFactoryMethod(kernel =>
{
return new MapperConfiguration(configuration =>
{
kernel.ResolveAll<Profile>().ToList().ForEach(configuration.AddProfile);
});
}).LifestyleSingleton());
// Register IMapper with registered IConfigurationProvider
container.Register(
Component.For<IMapper>().UsingFactoryMethod(kernel =>
new Mapper(kernel.Resolve<IConfigurationProvider>(), kernel.Resolve)));
}
}
Catel.IoC
对于那些使用 Catel.IoC 的用户,下面介绍如何注册自动控制器。首先使用配置文件定义配置。然后你让 AutoMapper 知道在哪些程序集中这些配置文件是通过在启动时在 ServiceLocator 中注册 AutoMapper 定义的:
配置创建方法:
public static MapperConfiguration CreateConfiguration()
{
var config = new MapperConfiguration(cfg =>
{
// Add all profiles in current assembly
cfg.AddMaps(GetType().Assembly);
});
return config;
}
现在你可以在运行时将 AutoMapper 注入到你的服务/控制器中:
public class EmployeesController {
private readonly IMapper _mapper;
public EmployeesController(IMapper mapper) => _mapper = mapper;
// use _mapper.Map or _mapper.ProjectTo
}
后记
本人不是大佬,只是道路先行者,在落河后,向后来的人大喊一声,这里有坑,不要过来啊!
纵然如此,依旧有人重复着落河,重复着呐喊······
个人博客网站 Blog
技术交流Q群: 1012481075 群内有各种流行书籍资料
文章后续会在公众号更新,微信搜索 OneByOneDotNet 即可关注。
你的一分鼓励,我的十分动力,点赞免费,感恩回馈。喜欢就点赞评论吧,双击6666~
AutoMapper 10.0使用教程的更多相关文章
- Adobe Audition CC 2017 (10.0)安装教程
Adobe Audition CC 2017 (10.0)安装教程 注:下载地址在文章末尾 第一步:首先请将电脑的网络断开,很简单:禁用本地连接或者拔掉网线,这样就可以免除登录Creative Clo ...
- 分享ArcGIS Server 10.0修复安装心得
最近,捣腾了一阵子在xp系统上安装ArcGIS Server10.0(下方均简称server),解决了一些初学者可能面临的problem,给大家贴出来, 希望能够给初学者一些有益的帮助. 我的系统环境 ...
- 【转】windows环境下安装win8.1+Mac OS X 10.10双系统教程
先要感谢远景论坛里的各位大神们的帖子 没有他们的分享我也不能顺利的装上Mac OS X 10.10! 写这篇随笔主要是为了防止自己遗忘,同时给大家分享下我的经验. 本教程适用于BIOS+MBR分区的 ...
- windows环境下安装win8.1+Mac OS X 10.10双系统教程
首先要感谢远景论坛里的各位大神们的帖子 没有他们的分享我也不能顺利的装上Mac OS X 10.10! 写这篇随笔主要是为了防止自己遗忘,同时给大家分享下我的经验. 本教程适用于BIOS+MBR分区 ...
- Windows环境下Android Studio v1.0安装教程
Windows环境下Android Studio v1.0安装教程 准备工具 JDK安装包. 要求:JDK 7以及以上版本. Android Studio安装文件. Windows: exe(包含SD ...
- Swift3.0语言教程使用路径字符串
Swift3.0语言教程使用路径字符串 Swift3.0语言教程使用路径字符串,路径其实是字符串的一种,我们称为路径字符串.本小节将讲解如何使用路径字符串. 1.组合路径 开发者可以将数组快速的组合成 ...
- Swift3.0语言教程删除字符与处理字符编码
Swift3.0语言教程删除字符与处理字符编码 Swift3.0语言教程删除字符 Swift3.0语言教程删除字符与处理字符编码,在字符串中,如果开发者有不需要使用的字符,就可以将这些字符删除.在NS ...
- Swift3.0语言教程组合字符串
Swift3.0语言教程组合字符串 Swift3.0语言教程组合字符串,当开发者想要将已经存在的字符串进行组合,形成一个新的字符串,可以使用NSString中的两个方法,分别为appending(_: ...
- EntityFramework 5.0 CodeFirst 教程04-查询,插入,更新,和删除数据
---------------------目录-------------------------- EntityFramework 5.0 CodeFirst 教程04-查询,插入,更新,和删除数据 ...
随机推荐
- 线程 - Java中的Copy-On-Write容器
http://ifeve.com/java-copy-on-write/ 什么是CopyOnWrite容器 CopyOnWrite容器即写时复制的容器.通俗的理解是当我们往一个容器添加元素的时候,不直 ...
- sendfile“零拷贝”和mmap内存映射
在学习sendfille之前,我们先来了解一下浏览器访问页面时,后台服务器的大致工作流程. 下图是从用户访问某个页面到页面的显示这几秒钟的时间当中,在后台的整个工作过程. 如上图,黑色箭头所示的过程, ...
- RocketMQ(十):数据存储模型设计与实现
消息中间件,说是一个通信组件也没有错,因为它的本职工作是做消息的传递.然而要做到高效的消息传递,很重要的一点是数据结构,数据结构设计的好坏,一定程度上决定了该消息组件的性能以及能力上限. 1. 消息中 ...
- TurtleBot3 Waffle (tx2版华夫)(4)笔记本与TX2的通信
4.1. 使用vnc控制华夫Turbot3-Tx2开发板 1) 电脑端安装vnc viewer,您可以选择应用商城下载安装即可: 2) 下载后打开,键入Turbot3的ip à回车à选择连接: 3) ...
- k8s之HTTP请求负载分发
一.导读 对于基于HTTP的服务来说,不同的URL地址经常对应不同的后端服务或者虚拟服务器,通常的做法是在应用前添加一个反向代理服务器Nginx,进行请求的负载转发,在Spring Cloud这个微服 ...
- Lesson_strange_words1
time-between system 分时操作:分时系统 secondary 辅助的,从属的 establish 已确立的 capability 功能 formerly 之前的 combine 结合 ...
- ios iphone 崩溃字符记录
如题,近日iphone被爆出有一串字符可引发系统错误 (بٍٍٍٍََُُُِّّّْرٍٍٍٍََُُِِّّّْآٍٍٍَُّ بٍٍٍٍََُُُِّّّْرٍٍٍٍََُُِِّّّْآٍٍٍ ...
- JavaCV更新到1.5.x版本后的依赖问题说明以及如何精简依赖包大小
javaCV全系列文章汇总整理 javacv教程文档手册开发指南汇总篇 前言 JavaCV更新到1.5.x版本,依赖包也迎来了很大变化,体积也变大了不少.很多小伙伴们反馈,之前很多1.3.x和1.4. ...
- LeetCode747 至少是其他数字两倍的最大数
在一个给定的数组nums中,总是存在一个最大元素 . 查找数组中的最大元素是否至少是数组中每个其他数字的两倍. 如果是,则返回最大元素的索引,否则返回-1. 示例 1: 输入: nums = [3, ...
- LeetCode53 最大子序列问题
题目描述: 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. 示例: 输入: [-2,1,-3,4,-1,2,1,-5,4], ...