Ejemplo n.º 1
0
 public AutoMapperAdapter(IConfigurationProvider configurationProvider)
 {
     _mapper = new global::AutoMapper.Mapper(configurationProvider);
 }
        /// <summary>
        /// 增加auto mapper自动化映射,注册了全局单例IMapper
        /// </summary>
        /// <param name="kernelService"></param>
        /// <param name="assemblies">需要注册的程序集</param>
        /// <returns></returns>
        public static IKernelServices AddAutoMapperByConvention(this IKernelServices kernelService,
                                                                IEnumerable <Assembly> assemblies)
        {
            if (assemblies is null)
            {
                throw new ArgumentNullException(nameof(assemblies));
            }

            var configuration = new MapperConfiguration(config =>
            {
                var method = config.GetType().GetTypeInfo().GetMethod("CreateMap", new Type[] { typeof(MemberList) });
                if (method is null || !method.IsGenericMethodDefinition)
                {
                    throw new MissingMethodException(nameof(IMapperConfigurationExpression), "CreateMap");
                }
                //.Single(r => r.Name == "CreateMap" && r.IsGenericMethodDefinition && r.GetParameters().Length == 1);

                foreach (var assembly in assemblies)
                {
                    var iMapFrom1Types = assembly.DefinedTypes.Where(r =>
                                                                     !r.IsAbstract && r.IsClass && r.IsSubTypeOfGenericType(typeof(IMapFrom <>))).ToList();
                    var iMapFromTypes = assembly.DefinedTypes.Where(r =>
                                                                    !r.IsAbstract && r.IsClass && r.IsSubTypeOfGenericType(typeof(IMapFrom <,>))).ToList();
                    var iMapTo1Types = assembly.DefinedTypes
                                       .Where(r => !r.IsAbstract && r.IsClass && r.IsSubTypeOfGenericType(typeof(IMapTo <>))).ToList();
                    var iMapToTypes = assembly.DefinedTypes.Where(r =>
                                                                  !r.IsAbstract && r.IsClass && r.IsSubTypeOfGenericType(typeof(IMapTo <,>))).ToList();

                    // IMapFrom<TFrom>
                    foreach (var item in iMapFrom1Types)
                    {
                        var interfaces = item.GetAllInterfaces(false);
                        var fromTypes  = interfaces
                                         .Where(r => r.IsGenericType && r.GenericTypeArguments.Length == 1 &&
                                                r.FullName !.StartsWith(typeof(IMapFrom <>).FullName !))
                                         .Select(r => r.GenericTypeArguments[0])
                                         .ToList();

                        foreach (var fromType in fromTypes)
                        {
                            config.CreateMap(fromType, item, MemberList.None);
                        }
                    }

                    // IMapFrom<TFrom, TDest>
                    foreach (var item in iMapFromTypes)
                    {
                        var interfaces = item.GetAllInterfaces(false);

                        var interfaceTypes = interfaces.Where(r =>
                                                              r.IsGenericType && r.GenericTypeArguments.Length == 2 &&
                                                              r.FullName !.StartsWith(typeof(IMapFrom <,>).FullName !)).ToHashSet();
                        if (interfaceTypes.IsNullOrEmpty())
                        {
                            continue;
                        }

                        foreach (var interfaceType in interfaceTypes)
                        {
                            var fromType = interfaceType.GenericTypeArguments[0];
                            var destType = interfaceType.GenericTypeArguments[1];

                            var expression = method.MakeGenericMethod(fromType, destType)
                                             .Invoke(config, new object[] { MemberList.None });
                            if (expression is null)
                            {
                                throw new InvalidConstraintException($"[AutoMapper] `CreateMap` method return null");
                            }
                            var expressionType = typeof(IMappingExpression <,>).MakeGenericType(fromType, destType);

                            var configMethod = item.GetMethods().First(r =>
                                                                       r.Name == "Config" && r.GetParameters().Length == 1 &&
                                                                       r.GetParameters().First().ParameterType == expressionType);

                            object?obj;
                            try
                            {
                                obj = Activator.CreateInstance(item);
                            }
                            catch
                            {
                                throw new InvalidConstraintException(
                                    $"[AutoMapper] can not create instance of {item}, must contains non-argument constructor");
                            }

                            if (obj is null)
                            {
                                throw new InvalidConstraintException(
                                    $"[AutoMapper] can not create instance of {item}, must contains non-argument constructor");
                            }
                            try
                            {
                                configMethod.Invoke(obj, new object[] { expression });
                                using (obj as IDisposable)
                                {
                                }
                            }
                            catch (Exception e)
                            {
                                throw new InvalidConstraintException(
                                    $"[AutoMapper] create mapper {fromType}->{destType} error on type {item}.", e);
                            }
                        }
                    }

                    // IMapTo < TDest >
                    foreach (var item in iMapTo1Types)
                    {
                        var interfaces = item.GetAllInterfaces(false);
                        var toTypes    = interfaces
                                         .Where(r => r.IsGenericType && r.GenericTypeArguments.Length == 1 &&
                                                r.FullName !.StartsWith(typeof(IMapTo <>).FullName !))
                                         .Select(r => r.GenericTypeArguments[0])
                                         .ToList();
                        if (toTypes.IsNullOrEmpty())
                        {
                            continue;
                        }
                        foreach (var toType in toTypes)
                        {
                            config.CreateMap(item, toType, MemberList.None);
                        }
                    }

                    // IMapTo<TDest, TSource>
                    foreach (var item in iMapToTypes)
                    {
                        var interfaces     = item.GetAllInterfaces(false);
                        var interfaceTypes = interfaces.Where(r =>
                                                              r.IsGenericType && r.GenericTypeArguments.Length == 2 &&
                                                              r.FullName !.StartsWith(typeof(IMapTo <,>).FullName !)).ToList();
                        if (interfaceTypes.IsNullOrEmpty())
                        {
                            continue;
                        }
                        foreach (var interfaceType in interfaceTypes)
                        {
                            var destType = interfaceType.GenericTypeArguments[0];
                            var fromType = interfaceType.GenericTypeArguments[1];

                            var expression = method.MakeGenericMethod(fromType, destType)
                                             .Invoke(config, new object[] { MemberList.None });
                            if (expression is null)
                            {
                                throw new InvalidConstraintException($"[AutoMapper] `CreateMap` method return null");
                            }
                            var expressionType = typeof(IMappingExpression <,>).MakeGenericType(fromType, destType);
                            var configMethod   = item.GetMethods().First(r =>
                                                                         r.Name == "Config" && r.GetParameters().Length == 1 &&
                                                                         r.GetParameters().First().ParameterType == expressionType);
                            object?obj;
                            try
                            {
                                obj = Activator.CreateInstance(item);
                            }
                            catch
                            {
                                throw new InvalidConstraintException(
                                    $"[AutoMapper] can not create instance of {item}, must contains non-argument constructor");
                            }

                            if (obj is null)
                            {
                                throw new InvalidConstraintException(
                                    $"[AutoMapper] can not create instance of {item}, must contains non-argument constructor");
                            }
                            try
                            {
                                configMethod.Invoke(obj, new object[] { expression });
                                using (obj as IDisposable)
                                {
                                }
                            }
                            catch (Exception e)
                            {
                                throw new InvalidConstraintException(
                                    $"[AutoMapper] create mapper {fromType}->{destType} error on type {item}.", e);
                            }
                        }
                    }
                }
            });

            configuration.AssertConfigurationIsValid();
            var mapper = new global::AutoMapper.Mapper(configuration);

            ShashlikAutoMapper.Instance = mapper;

            kernelService.Services.AddSingleton <IMapper>(mapper);
            return(kernelService);
        }