最近在研究ABP项目,昨天写了Castle Windsor常用介绍以及其在ABP项目的应用介绍 欢迎各位拍砖,有关ABP的介绍请看阳光铭睿 博客

AutoMapper只要用来数据转换,在园里已经有很多这方面文章了,本文主要介绍其在实际项目常用总结,以及在ABP项目中的应用介绍。AutoMapper应用非常简单,大家稍微看下文档就可以上手,但是性能不好啊,所以一般用在后台项目,对外的项目千万不要用。就那NOP来说吧,它也是把AutoMapper放在后台项目使用,商城前台的项目是不敢用的。

有关性能的问题本文没有涉及到,想了解的请参考EmitMapper,AutoMapper,NLiteMapper和手工映射性能大比拼 和 NLiteMapper与EmitMapper性能简单比较

下面主要讲下项目的入门和项目中的使用。

AutoMapper使用只要两步,配置和Mapper,一般的在项目中我们会在Global中进行配置

配置映射关系

public class Source
{
public int SomeValue { get; set; }
} public class Destination
{
public int SomeValue { get; set; }
} //这个就是配置映射关系
Mapper.CreateMap<Source, Destination>();

然后就是Mapper

Source source = new Source()
{
SomeValue = 1
}; var destination = Mapper.Map<Source, Destination>(source);
Console.WriteLine(destination.SomeValue);//1

是不是很简单,这是最简单的使用了,当然AutoMapper是个“机关枪”,这个只是它的最简单使用。下面在介绍几点常用的功能。还是上面那个例子,只是字段变了

    public class Source
{
public int SomeValue { get; set; }
} public class Destination
{
public int SomeValuefff { get; set; }
} Mapper.CreateMap<AddressDto, Address>();

这样子字段都不一样明细是不能映射的嘛,所有呢我们可以用Mapper.AssertConfigurationIsValid()来验证,就会AutoMapperConfigurationException异常,

选择忽略相关字段

Mapper.CreateMap<Source, Destination>()
.ForMember(dest => dest.SomeValuefff, opt => opt.Ignore());

类型转换,自定义类型转换

    public class Source
{
public string Value1 { get; set; }
public string Value2 { get; set; }
public string Value3 { get; set; }
} public class Destination
{
public int Value1 { get; set; }
public DateTime Value2 { get; set; }
public Type Value3 { get; set; }
}

Source要转Destination,但是第二和第三的字段类型都不一致,所以我们可以自定义类型转换,下面看下转换函数ConvertUsing一般最常用第二种,接受一个ITypeConverter

    void ConvertUsing(Func<TSource, TDestination> mappingFunction);
void ConvertUsing(ITypeConverter<TSource, TDestination> converter);
void ConvertUsing<TTypeConverter>() where TTypeConverter : ITypeConverter<TSource, TDestination>;

下面看下ITypeConverter接口

    public interface ITypeConverter<TSource, TDestination>
{
TDestination Convert(ResolutionContext context);
}

我们可以继承这个接口队Convert进行重写

    public class DateTimeTypeConverter : ITypeConverter<string, DateTime>
{
public DateTime Convert(ResolutionContext context)
{
return System.Convert.ToDateTime(context.SourceValue);
}
} public class TypeTypeConverter : ITypeConverter<string, Type>
{
public Type Convert(ResolutionContext context)
{
return context.SourceType;
}
}

这样我们就可以映射了,下面看下完整代码

    public void Example()
{
Mapper.CreateMap<string, int>().ConvertUsing(Convert.ToInt32);
Mapper.CreateMap<string, DateTime>().ConvertUsing(new DateTimeTypeConverter());
Mapper.CreateMap<string, Type>().ConvertUsing<TypeTypeConverter>();
Mapper.CreateMap<Source, Destination>();
Mapper.AssertConfigurationIsValid(); var source = new Source
{
Value1 = "5",
Value2 = "01/01/2000",
Value3 = "AutoMapperSamples.GlobalTypeConverters.GlobalTypeConverters+Destination"
}; Destination result = Mapper.Map<Source, Destination>(source);
result.Value3.ShouldEqual(typeof (Destination));
} public class DateTimeTypeConverter : ITypeConverter<string, DateTime>
{
public DateTime Convert(ResolutionContext context)
{
return System.Convert.ToDateTime(context.SourceValue);
}
} public class TypeTypeConverter : ITypeConverter<string, Type>
{
public Type Convert(ResolutionContext context)
{
return context.SourceType;
}
}

好了,上面把 AutoMapper在项目中常用的方法都介绍完了,再介绍ABP之前我们先看下NOP是怎么使用的吧,由于代码较长省略部分

    public class AutoMapperStartupTask : IStartupTask
{
public void Execute()
{
//TODO remove 'CreatedOnUtc' ignore mappings because now presentation layer models have 'CreatedOn' property and core entities have 'CreatedOnUtc' property (distinct names) //address
Mapper.CreateMap<Address, AddressModel>()
.ForMember(dest => dest.AddressHtml, mo => mo.Ignore())
.ForMember(dest => dest.CustomAddressAttributes, mo => mo.Ignore())
.ForMember(dest => dest.FormattedCustomAddressAttributes, mo => mo.Ignore())
.ForMember(dest => dest.AvailableCountries, mo => mo.Ignore())
.ForMember(dest => dest.AvailableStates, mo => mo.Ignore())
.ForMember(dest => dest.FirstNameEnabled, mo => mo.Ignore())
.ForMember(dest => dest.FirstNameRequired, mo => mo.Ignore())
.ForMember(dest => dest.LastNameEnabled, mo => mo.Ignore())
.ForMember(dest => dest.LastNameRequired, mo => mo.Ignore())
.ForMember(dest => dest.EmailEnabled, mo => mo.Ignore())
.ForMember(dest => dest.EmailRequired, mo => mo.Ignore())
.ForMember(dest => dest.CompanyEnabled, mo => mo.Ignore())
.ForMember(dest => dest.CompanyRequired, mo => mo.Ignore())
.ForMember(dest => dest.CountryEnabled, mo => mo.Ignore())
.ForMember(dest => dest.StateProvinceEnabled, mo => mo.Ignore())
...

好了,终于可以到ABP的了,ABP对AutoMapper的使用总结出来两点,1、在模块中初始化配置,2、遍历bin目录下所有的Types判断哪些类是否被定义为需要转换的Attribute

在模块中初始化配置

    public class AbpAutoMapperModule : AbpModule
{
private readonly ITypeFinder _typeFinder; private static bool _createdMappingsBefore;
private static readonly object _syncObj = new object(); public AbpAutoMapperModule(ITypeFinder typeFinder)
{
_typeFinder = typeFinder;
} private void FindAndAutoMapTypes()
{
var types = _typeFinder.Find(type =>
type.IsDefined(typeof(AutoMapAttribute)) ||
type.IsDefined(typeof(AutoMapFromAttribute)) ||
type.IsDefined(typeof(AutoMapToAttribute))
); foreach (var type in types)
{
AutoMapperHelper.CreateMap(type);
}
}
}

AbpAutoMapperModule 模块会在Global的时候被初始化,然后在PreInitialize的时候回调用到FindAndAutoMapTypes,有关模块是怎么初始化的我想再写一篇介绍。下面我们看下_typeFinder吧

上面_typeFinder.Find调用的是TypeFinder的Find方法

        public Type[] Find(Func<Type, bool> predicate)
{
return GetAllTypes().Where(predicate).ToArray();
} public Type[] FindAll()
{
return GetAllTypes().ToArray();
} private List<Type> GetAllTypes()
{
var allTypes = new List<Type>(); foreach (var assembly in AssemblyFinder.GetAllAssemblies().Distinct())
{
try
{
Type[] typesInThisAssembly; try
{
typesInThisAssembly = assembly.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
typesInThisAssembly = ex.Types;
} if (typesInThisAssembly.IsNullOrEmpty())
{
continue;
} allTypes.AddRange(typesInThisAssembly.Where(type => type != null));
}
catch (Exception ex)
{
Logger.Warn(ex.ToString(), ex);
}
} return allTypes;
}

好吧,上面代码有点多,但是很简单,就是获取所有的Types,我们看下关键代码AssemblyFinder.GetAllAssemblies()

    public class WebAssemblyFinder : IAssemblyFinder
{
/// <summary>
/// This return all assemblies in bin folder of the web application.
/// </summary>
/// <returns>List of assemblies</returns>
public List<Assembly> GetAllAssemblies()
{
var assembliesInBinFolder = new List<Assembly>(); var allReferencedAssemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToList();
var dllFiles = Directory.GetFiles(HttpRuntime.AppDomainAppPath + "bin\\", "*.dll", SearchOption.TopDirectoryOnly).ToList(); foreach (string dllFile in dllFiles)
{
var locatedAssembly = allReferencedAssemblies.FirstOrDefault(asm => AssemblyName.ReferenceMatchesDefinition(asm.GetName(), AssemblyName.GetAssemblyName(dllFile)));
if (locatedAssembly != null)
{
assembliesInBinFolder.Add(locatedAssembly);
}
} return assembliesInBinFolder;
}
}

看看吧,这代码是或bin目录下面的dll,好丧心病狂啊,回到刚刚AbpAutoMapperModule 的获取FindAndAutoMapTypes方法。在获取所有的Types之后我们就要判断这个类是否是被标识了

AutoMapAttribute、AutoMapFromAttribute和AutoMapToAttribute

        private void FindAndAutoMapTypes()
{
var types = _typeFinder.Find(type =>
type.IsDefined(typeof(AutoMapAttribute)) ||
type.IsDefined(typeof(AutoMapFromAttribute)) ||
type.IsDefined(typeof(AutoMapToAttribute))
); foreach (var type in types)
{
AutoMapperHelper.CreateMap(type);
}
}

获取之后再我下的Demo中就只有一个UserDto类被标识了 

namespace AbpDemo.Application.Users.Dto
{
[AutoMapFrom(typeof(User))]
public class UserDto : EntityDto<long>
{
public string UserName { get; set; } public string Name { get; set; } public string Surname { get; set; } public string EmailAddress { get; set; }
}
}

接下来就是遍历所有的types进行配置了AutoMapperHelper.CreateMap(type);配置也很简单 看下代码

        public static void CreateMap<TAttribute>(Type type)
where TAttribute : AutoMapAttribute
{
if (!type.IsDefined(typeof (TAttribute)))
{
return;
} foreach (var autoMapToAttribute in type.GetCustomAttributes<TAttribute>())
{
if (autoMapToAttribute.TargetTypes.IsNullOrEmpty())
{
continue;
} foreach (var targetType in autoMapToAttribute.TargetTypes)
{
if (autoMapToAttribute.Direction.HasFlag(AutoMapDirection.To))
{
Mapper.CreateMap(type, targetType);
} if (autoMapToAttribute.Direction.HasFlag(AutoMapDirection.From))
{
Mapper.CreateMap(targetType, type);
}
}
}
}

好了,表达能力不是很好,各位就勉强看下吧。终于写完了。发现作者很喜欢用Attribute来过滤。这边AutoMapper是这样,UnitOfWork也是这样,其实这样也是挺方便的,有点AOP的切面的感觉,值得学习。 

参考文章:

http://www.cnblogs.com/netcasewqs/archive/2011/04/13/2014684.html

http://www.cnblogs.com/repository/archive/2011/04/08/2009713.html

https://github.com/AutoMapper/AutoMapper/wiki/Configuration-validation

http://www.cnblogs.com/youring2/p/automapper.html

http://www.cnblogs.com/1-2-3/p/AutoMapper-Best-Practice.html

AutoMapper之ABP项目中的使用介绍的更多相关文章

  1. ABP项目中的使用AutoMapper

    AutoMapper之ABP项目中的使用 最近在研究ABP项目,昨天写了Castle Windsor常用介绍以及其在ABP项目的应用介绍 欢迎各位拍砖,有关ABP的介绍请看阳光铭睿 博客 AutoMa ...

  2. AutoMapper在ABP框架中的使用说明

    为了说明AutoMapper如何使用,我专门开设了一个专题来讲,如果您还没有查看该专题,请点击这里.既然系统地学习了AutoMapper,那么接下来就是该用它实战的时候了.今天,我们就来揭开AutoM ...

  3. 说说ABP项目中的AutoMapper,Castle Windsor(痛并快乐着)

    这篇博客要说的东西跟ABP,AutoMapper和Castle Windsor都有关系,而且也是我在项目中遇到的问题,最终解决了,现在的感受就是“痛并快乐着”. 首先,这篇博客不是讲什么新的知识点,而 ...

  4. ABP项目中使用Swagger生成动态WebAPI

    本文是根据角落的白板报的<使用ABP实现SwaggerUI,生成动态webapi>一文的学习总结,感谢原文作者角落的白板报. 1 安装Swashbuckle.core 1.1 选择WebA ...

  5. 在基于AngularJs架构的ABP项目中使用UEditor

    [前提须知] 读过此篇博客 了解angular-ueditor 了解ABP如何使用 会使用VS2017 [1.下载ABP模板] https://aspnetboilerplate.com/Templa ...

  6. 开源物联网框架ServerSuperIO(SSIO),项目中实践应用介绍

    一.项目背景 我们是传统行业,但是我们有一颗不传统的心.企业用户遍布国内和国外,面对行业,要建设行业级的(大)数据平台.一提到大数据平台,大家往往想到Hadoop.Spark.Nosql.分布式等等, ...

  7. Abp项目中的领域模型实体类访问仓储的方法

    首先声明,不推荐使用这种方法.实体访问仓储是不被推荐的! 1.简单粗暴的方法 Abp.Dependency.IocManager.Instance.Resolve>(); 2.绕个弯子的方法 首 ...

  8. abp项目中无法使用HttpContext.Current.Session[""]的问题

    web项目Global.asax.cs中加入如下代码 public override void Init() { this.PostAuthenticateRequest += (sender, e) ...

  9. axios在实际项目中的使用介绍

    1.axios本身就封装了各种数据请求的方法 执行 GET 请求 // 为给定 ID 的 user 创建请求 axios.get('/user?ID=12345') .then(function (r ...

随机推荐

  1. 删除数据表中除id外其他字段相同的冗余信息

    删除一个信息表中除id外其他字段都相同的冗余信息,如下 id name addr 1 a b 2 a b 3 b c 删除这个表中的冗余信息 即应该是 id name addr 1 a b 3 b c ...

  2. Java_IO流_File类配合使用(其中用到了递归)

    第一:Java File类的功能非常强大,利用Java基本上可以对文件进行所有的操作.以下对Java File文件操作以及常用方法进行简单介绍 案例1:遍历出指定目录下的文件夹,并输出文件名 stat ...

  3. oc集合

    本人之前学习过一年半ios开发 由于行情太过凄惨,故转前端.心在前端,苹果亦难忘!把我平时的笔记作出给大家总结! 回顾之前的知识 便利初始化函数:框架类库中的一些类有一系列的以init开头的方法,这些 ...

  4. WaitType:ASYNC_IO_COMPLETION

    项目组有一个数据库备份的Job运行异常,该Job将备份数据存储到remote server上,平时5个小时就能完成的备份操作,现在运行19个小时还没有完成,backup命令的Wait type是 AS ...

  5. SQL Server 自动增长过大

    一.背景 我们遇到的问题如下图所示:自动增长无端端就按照这样的比例进行增长: (Figure1:问题所在) 尝试使用SSMS修改自动增长值,就会出现下面的错误: (Figure2:错误信息) 遇到上面 ...

  6. 【Win10应用开发】自适应磁贴中的分组

    老周在上一篇文章中介绍过了自适应磁贴的基本结构,以及给大家演示了一些例子. 本文老周给大伙伴们说说自适应磁贴的另一个特点——分组呈现. 当磁贴的内容被分组后,每个组中的内容就会被视为一个整体.比如某磁 ...

  7. ClickOnce部署(2):自动更新

    上次我们说了如何用最基本的方式用ClickOnce技术部署应用程序项目,本篇我们来认识一下如何让应用程序具备自动更新的功能. 我们依然通过实例来学习. 第一步,随便建一个应用程序项目,至于是控制台.W ...

  8. 通过SSH连接linux服务器

    SSH 为 Secure Shell 的缩写,由 IETF 的网络工作小组(Network Working Group)所制定:SSH 为建立在应用层和传输层基础上的安全协议.SSH 是目前较可靠,专 ...

  9. 【记录】SqlBulkCopy 跨数据库,表自定义导入

    使用场景: 一个数据库中的表数据,导入到另一个数据库中的表中,这两个表的表结构不一样,如果表结构一样的时候,导入非常简单,直接读取导入就行了,表结构不一样,就意味着需要加入一些判断,SqlBulkCo ...

  10. C# 提取Word文档中的图片

    C# 提取Word文档中的图片 图片和文字是word文档中两种最常见的对象,在微软word中,如果我们想要提取出一个文档内的图片,只需要右击图片选择另存为然后命名保存就可以了,今天这篇文章主要是实现使 ...