ABP項目中的使用AutoMapper


AutoMapper之ABP項目中的使用

最近在研究ABP項目,昨天寫了Castle Windsor常用介紹以及其在ABP項目的應用介紹 歡迎各位拍磚,有關ABP的介紹請看陽光銘睿 博客

AutoMapper只要用來數據轉換,在園里已經有很多這方面文章了,本文主要介紹其在實際項目常用總結,以及在ABP項目中的應用介紹。AutoMapper應用非常簡單,大家稍微看下文檔就可以上手,但是性能不好啊,所以一般用在后台項目,對外的項目千萬不要用。就那NOP來說吧,它也是把AutoMapper放在后台項目使用,商城前台的項目是不敢用的。

有關性能的問題本文沒有涉及到,想了解的請參考EmitMapper,AutoMapper,NLiteMapper和手工映射性能大比拼 和 NLiteMapper與EmitMapper性能簡單比較

下面主要講下項目的入門和項目中的使用。

 

AutoMapper使用只要兩步,配置和Mapper,一般的在項目中我們會在Global中進行配置

配置映射關系

1
2
3
4
5
6
7
8
9
10
11
12
public  class  Source
{
    public  int  SomeValue {  get set ; }
}
 
public  class  Destination
{
    public  int  SomeValue {  get set ; }
}
 
//這個就是配置映射關系
Mapper.CreateMap<Source, Destination>();

然后就是Mapper

1
2
3
4
5
6
7
Source source =  new  Source()
{
     SomeValue = 1
};
 
var  destination = Mapper.Map<Source, Destination>(source);
Console.WriteLine(destination.SomeValue); //1

是不是很簡單,這是最簡單的使用了,當然AutoMapper是個“機關槍”,這個只是它的最簡單使用。下面在介紹幾點常用的功能。還是上面那個例子,只是字段變了

1
2
3
4
5
6
7
8
9
10
11
public  class  Source
{
     public  int  SomeValue {  get set ; }
}
 
public  class  Destination
{
     public  int  SomeValuefff {  get set ; }
}
 
Mapper.CreateMap<AddressDto, Address>();

這樣子字段都不一樣明細是不能映射的嘛,所有呢我們可以用Mapper.AssertConfigurationIsValid()來驗證,就會AutoMapperConfigurationException異常,

選擇忽略相關字段

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

類型轉換,自定義類型轉換

1
2
3
4
5
6
7
8
9
10
11
12
13
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

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

下面看下ITypeConverter接口

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

我們可以繼承這個接口隊Convert進行重寫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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是怎么使用的吧,由於代碼較長省略部分

好了,終於可以到ABP的了,ABP對AutoMapper的使用總結出來兩點,1、在模塊中初始化配置,2、遍歷bin目錄下所有的Types判斷哪些類是否被定義為需要轉換的Attribute

在模塊中初始化配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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

1
2
3
4
5
6
7
8
9
10
11
12
13
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類被標識了 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);配置也很簡單 看下代碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM