zoukankan      html  css  js  c++  java
  • 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 { getset; }
    }
     
    public class Destination
    {
       public int SomeValue { getset; }
    }
     
    //这个就是配置映射关系
    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 { getset; }
    }
     
    public class Destination
    {
        public int SomeValuefff { getset; }
    }
     
    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 { getset; }
        public string Value2 { getset; }
        public string Value3 { getset; }
    }
     
    public class Destination
    {
        public int Value1 { getset; }
        public DateTime Value2 { getset; }
        public Type Value3 { getset; }
    }

    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 { getset; }
     
            public string Name { getset; }
             
            public string Surname { getset; }
             
            public string EmailAddress { getset; }
        }
    }

    接下来就是遍历所有的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

  • 相关阅读:
    June 26th 2017 Week 26th Monday
    June 25th 2017 Week 26th Sunday
    June 24th 2017 Week 25th Saturday
    June 23rd 2017 Week 25th Friday
    June 22nd 2017 Week 25th Thursday
    2018最佳网页设计:就是要你灵感爆棚!!!
    图片素材类Web原型制作分享-Pexels
    想要打动HR的心,UX设计师求职信究竟应该怎么写?
    【UXPA大赛企业专访】Mockplus:“设计替代开发”将成为现实
    2018年最好的医疗网站设计及配色赏析
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4836973.html
Copyright © 2011-2022 走看看