• 对象映射模块


    一、ObjectMapping 对象映射

    在应用层应用

        public override void ConfigureServices(ServiceConfigurationContext context)
            {
                context.Services.AddAutoMapperObjectMapper<***ApplicationModule>(); 
                Configure<AbpAutoMapperOptions>(options =>
                {
                    options.AddProfile<***ApplicationAutoMapperProfile>(validate: true);
                }
    
    
      public class ***ApplicationAutoMapperProfile : Profile
        {
            public ***ApplicationAutoMapperProfile()
            {
                CreateMap<***, **Dto>().Ignore(t=>t.**);
                CreateMap<***, ***Dto>();
            }
        }
    
      public abstract class ***AppServiceBase : ApplicationService
        {
            protected ***AppServiceBase()
            {
                ObjectMapperContext = typeof(***ApplicationModule);
                LocalizationResource = typeof(***Resource);
            }
        }

     定义的接口IObjectMapper和默认的实现类DefaultObjectMapper

    1、它首先使用IObjectMapper<TSource, TDestination>的实现方法,这个泛型方法注入需要单独注入,它在模块的ConfigureServices的OnExposing进行注册,只要servicecollection的实现类实现IObjectMapper<,>,将其注册类型全部增加,检查包括自身以及其下所有接口类型

    2、然后是需要映射的Source是否是IMapTo<TDestination>,mapperSource.MapTo();

    3、是否是typeof(IMapFrom<TSource>).IsAssignableFrom(typeof(TDestination)

    4、最后是使用AutoObjectMappingProvider进行映射

    /// <summary>
        /// Defines a simple interface to automatically map objects.
        /// </summary>
        public interface IObjectMapper
        {
            /// <summary>
            /// Converts an object to another. Creates a new object of <see cref="TDestination"/>.
            /// </summary>
            /// <typeparam name="TDestination">Type of the destination object</typeparam>
            /// <typeparam name="TSource">Type of the source object</typeparam>
            /// <param name="source">Source object</param>
            TDestination Map<TSource, TDestination>(TSource source);
    
            /// <summary>
            /// Execute a mapping from the source object to the existing destination object
            /// </summary>
            /// <typeparam name="TSource">Source type</typeparam>
            /// <typeparam name="TDestination">Destination type</typeparam>
            /// <param name="source">Source object</param>
            /// <param name="destination">Destination object</param>
            /// <returns>Returns the same <see cref="destination"/> object after mapping operation</returns>
            TDestination Map<TSource, TDestination>(TSource source, TDestination destination);
        }
        /// <summary>
        /// Maps an object to another.
        /// Implement this interface to override object to object mapping for specific types.
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TDestination"></typeparam>
        public interface IObjectMapper<in TSource, TDestination>
        {
            /// <summary>
            /// Converts an object to another. Creates a new object of <see cref="TDestination"/>.
            /// </summary>
            /// <param name="source">Source object</param>
            TDestination Map(TSource source);
    
            /// <summary>
            /// Execute a mapping from the source object to the existing destination object
            /// </summary>
            /// <param name="source">Source object</param>
            /// <param name="destination">Destination object</param>
            /// <returns>Returns the same <see cref="destination"/> object after mapping operation</returns>
            TDestination Map(TSource source, TDestination destination);
        }

    2、AutoMapper

    automapper已经删除静态使用Initialize方法, new MapperConfiguration(Action<IMapperConfigurationExpression> configure)来初始化AutoMapper

    如果很多的Mapper.CreateMap调用把它们移动到一个Profile,而且IMapperConfigurationExpression.AddMaps(assembly)方法将查找模块内所有Profile增加到配置里面

    var config = new MapperConfiguration(cfg => cfg.CreateMap<Order, OrderDto>());
    var mapper = config.CreateMapper(); 

    为了实现上述操作,Abp创建AbpAutoMapperOptions,封装了ValidatingProfiles、Configurators即List<Action<IAbpAutoMapperConfigurationContext>>,而将IMapperConfigurationExpression封装在IAbpAutoMapperConfigurationContext里面

    体会下述封装的思想和操作,为什么要把ServiceProvider封装进去啊

     using (var scope = serviceProvider.CreateScope())
                {
                    var options = scope.ServiceProvider.GetRequiredService<IOptions<AbpAutoMapperOptions>>().Value;
                    void ConfigureAll(IAbpAutoMapperConfigurationContext ctx)
                    {
                        foreach (var configurator in options.Configurators)
                        {
                            configurator(ctx);
                        }
                    }
                    void ValidateAll(IConfigurationProvider config)
                    {
                        foreach (var profileType in options.ValidatingProfiles)
                        {
                            config.AssertConfigurationIsValid(((Profile)Activator.CreateInstance(profileType)).ProfileName);
                        }
                    }
                    var mapperConfiguration = new MapperConfiguration(mapperConfigurationExpression =>
                    {                   
                        ConfigureAll(new AbpAutoMapperConfigurationContext(mapperConfigurationExpression, scope.ServiceProvider));
                    });
                    ValidateAll(mapperConfiguration);
                    scope.ServiceProvider.GetRequiredService<MapperAccessor>().Mapper = mapperConfiguration.CreateMapper();
                }

    使用时,先创建一个Profile 类

    public class MyProfile : Profile
    {
        public MyProfile()
        {
            CreateMap<User, UserDto>();
        }
    }

    配置AbpAutoMapperOptions,AddMaps 注册给定类的程序集中所有的配置类,通常使用模块类. 它还会注册 attribute 映射.

     Configure<AbpAutoMapperOptions>(options =>
     {
          options.AddMaps<AutoMapperTestModule>();
     });
    options.AddMaps,实则执行了增加委托列表,在上面ConfigureAll执行,在AbpAutoMapperModule的OnPreApplicationInitialization执行
    Configurators.Add(context =>
                {
                    context.MapperConfiguration.AddMaps(assembly);
     });

    Because AutoMapper already provides it out of the box.

    I should think on that. If AutoMapper already has these attributes, we may consider to remove ours.

    Remove ABP's AutoMap attributes #1706

     

     

    配置验证

     

    AddMaps 使用可选的 bool 参数控制模块配置验证:

     

    options.AddMaps<MyModule>(validate: true);

     

    如果此选项默认是 false , 但最佳实践建议启用.

     

    可以使用 AddProfile 而不是 AddMaps 来控制每个配置文件类的配置验证:

     

    options.AddProfile<MyProfile>(validate: true);

     

    如果你有多个配置文件,并且只需要为其中几个启用验证,那么首先使用AddMaps而不进行验证,然后为你想要验证的每个配置文件使用AddProfile

     

     

     

    IObjectMapper<TContext>将对象映射器上下文化,你可以为不同的 模块/上下文 使用不同的库

     虽然使用上下文化的对象映射器与普通的对象映射器相同, 但是也应该在模块的 ConfigureServices 方法中注册上下文化的映射器:

     IObjectMapper<MyModule>是可重用模块的一项基本功能,可在多个应用程序中使用,每个模块可以使用不同的库进行对象到对象的映射. 所有预构建的ABP模块都在使用它. 但是对于最终应用程序,你可以忽略此接口,始终使用默认的 IObjectMapper 接口.

    关于OnExposing与OnRegistred委托方法

    IOnServiceExposingContext与IOnServiceRegistredContext作为操作对象分别注册到ServiceRegistrationActionList与ServiceExposingActionList里面

     public interface IOnServiceExposingContext
        {
            Type ImplementationType { get; }
            List<Type> ExposedTypes { get; }
        }
      public interface IOnServiceRegistredContext
        {
            ITypeList<IAbpInterceptor> Interceptors { get; }
            Type ImplementationType { get; }
        }

     》ServiceRegistrationActionList在Autofac进行服务注册时使用,每个服务与实现都执行委托的内容,如果拦截器Interceptors不为空,则egistrationBuilder.InterceptedBy里面,当创建服务注入按顺序创建相应的服务

    》ServiceExposingActionList在ConventionalRegistrarBase在服务自动注册时使用,它首先在Assembly得到所有type,筛选出type.IsClass列表,根据type和属性查到了LifeTime,根据type找到ExposedService作为serviceType,就是在实现类class注册到IServiceCollection,可以根据用户定义将多个ServiceType注册成该实现类

     var serviceDescriptor = ServiceDescriptor.Describe(serviceType, type, lifeTime.Value);
    IObjectMapper<,>  IObjectSerializer<>

    ExposedTypes就是ServiceType,implementationType就是Type

        context.Services.OnExposing(onServiceExposingContext =>
                {
                    //Register types for IObjectMapper<TSource, TDestination> if implements
                    onServiceExposingContext.ExposedTypes.AddRange(
                        ReflectionHelper.GetImplementedGenericTypes(
                            onServiceExposingContext.ImplementationType,
                            typeof(IObjectMapper<,>)
                        )
                    );
                });
    
    
    result是ServiceType列表,用于注册,GivenType是ClassType,genericType是IObjectMapper<,>
    private static void AddImplementedGenericTypes(List<Type> result, Type givenType, Type genericType)  
            {
                var givenTypeInfo = givenType.GetTypeInfo();
                if (givenTypeInfo.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
                {
                    result.Add(givenType);
                }
    
                foreach (var interfaceType in givenTypeInfo.GetInterfaces())
                {
                    if (interfaceType.GetTypeInfo().IsGenericType && interfaceType.GetGenericTypeDefinition() == genericType)
                    {
                        result.Add(interfaceType);
                    }
                }
                if (givenTypeInfo.BaseType == null)
                {
                    return;
                }
    
                AddImplementedGenericTypes(result, givenTypeInfo.BaseType, genericType);
            }
  • 相关阅读:
    dotnet logging serilog support
    普通索引和唯一索引,应该怎么选择?
    怎么减少行锁对性能的影响?
    全局锁和表锁 :给表加个字段怎么有这么多阻碍?
    Python调用函数模板
    Shell语言开发基础模板
    Python语言开发小工具库
    笔记day02
    笔记day06
    第2周需求
  • 原文地址:https://www.cnblogs.com/cloudsu/p/11231033.html
Copyright © 2020-2023  润新知