【问题标题】:Using AutoMapper.Profile for creating an instance(non-static) mapper使用 AutoMapper.Profile 创建实例(非静态)映射器
【发布时间】:2015-05-18 18:42:45
【问题描述】:

我使用以下答案中描述的以下方法来创建映射器的实例:

var platformSpecificRegistry = AutoMapper.Internal.PlatformAdapter.Resolve<IPlatformSpecificMapperRegistry>();
platformSpecificRegistry.Initialize();

var autoMapperCfg = new AutoMapper.ConfigurationStore(new TypeMapFactory(), AutoMapper.Mappers.MapperRegistry.Mappers);
var mappingEngine = new AutoMapper.MappingEngine(_autoMapperCfg);

如以下问题所述:

AutoMapper How To Map Object A To Object B Differently Depending On Context.

我如何能够使用[重用]Automapper profile 类来创建映射器的实例?

public class ApiTestClassToTestClassMappingProfile : Profile
{
    protected override void Configure()
    {
        base.Configure();
        Mapper.CreateMap<ApiTestClass, TestClass>()
            .IgnoreAllNonExisting();
    }
}

只是为了让您了解我为什么需要这样的功能: 我使用以下方法将所有 Automapper Profile 类注册到我的 IoC 容器 [CastleWindsor] 中:

    IoC.WindsorContainer.Register(Types.FromThisAssembly()
                                       .BasedOn<Profile>()
                                       .WithServiceBase()
                                       .Configure(c => c.LifeStyle.Is(LifestyleType.Singleton)));

    var profiles = IoC.WindsorContainer.ResolveAll<Profile>();

    foreach (var profile in profiles)
    {
        Mapper.AddProfile(profile);
    }

    IoC.WindsorContainer.Register(Component.For<IMappingEngine>().Instance(Mapper.Engine));

虽然上面完全满足了初始化我的静态 Mapper 类的需要,但我真的不知道如何重用我的 Automapper 配置文件类来创建实例映射器 [使用非静态映射器]。

【问题讨论】:

    标签: c# castle-windsor automapper ioc-container


    【解决方案1】:

    这就是您使用配置文件创建 MapperConfiguration 的方式

    public static class MappingProfile
    {
        public static MapperConfiguration InitializeAutoMapper()
        {
            MapperConfiguration config = new MapperConfiguration(cfg =>
            {
                cfg.AddProfile(new WebMappingProfile());  //mapping between Web and Business layer objects
                cfg.AddProfile(new BLProfile());  // mapping between Business and DB layer objects
            });
    
            return config;
        }
    }
    

    配置文件示例

    //Profile number one saved in Web layer
    public class WebMappingProfile : Profile
    {
        public WebMappingProfile()
        {
            CreateMap<Question, QuestionModel>();
            CreateMap<QuestionModel, Question>();
            /*etc...*/
        }
    }
    
    //Profile number two save in Business layer
    public class BLProfile: Profile
    {
        public BLProfile()
        {
            CreateMap<BLModels.SubModels.Address, DataAccess.Models.EF.Address>();
            /*etc....*/
        }
    }
    

    将自动映射器连接到 DI 框架(这是 Unity)

    public static class UnityWebActivator
    {
        /// <summary>Integrates Unity when the application starts.</summary>
        public static void Start()
        {
            var container = UnityConfig.GetConfiguredContainer();
            var mapper = MappingProfile.InitializeAutoMapper().CreateMapper();
            container.RegisterInstance<IMapper>(mapper);
    
            FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
            FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));
    
            DependencyResolver.SetResolver(new UnityDependencyResolver(container));
    
            // TODO: Uncomment if you want to use PerRequestLifetimeManager
            // Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
        }
    
        /// <summary>Disposes the Unity container when the application is shut down.</summary>
        public static void Shutdown()
        {
            var container = UnityConfig.GetConfiguredContainer();
            container.Dispose();
        }
    }
    

    在你的类中使用 IMapper 进行映射

    public class BaseService
    {
        protected IMapper _mapper;
    
        public BaseService(IMapper mapper)
        {
            _mapper = mapper;
        }
    
        public void AutoMapperDemo(){
            var questions = GetQuestions(token);
            return _mapper.Map<IEnumerable<Question>, IEnumerable<QuestionModel>>(questions);
        }
    
        public IEnumerable<Question> GetQuestions(token){
            /*logic to get Questions*/
        }
    }
    

    我的原帖可以在这里找到:http://www.codeproject.com/Articles/1129953/ASP-MVC-with-Automapper-Profiles

    【讨论】:

    • 此解决方案是否适用于 mvc 核心应用程序中的 Automapper V10?
    • 自 1 小时以来我一直在寻找此信息。谢谢。
    【解决方案2】:

    您需要确保您的个人资料调用正确的 CreateMap 调用:

    public class ApiTestClassToTestClassMappingProfile : Profile
    { 
        protected override void Configure()
        {
            CreateMap<ApiTestClass, TestClass>()
                .IgnoreAllNonExisting();
        }
    }
    

    基本 Profile 类上的 CreateMap 将该映射与该配置文件和配置相关联。

    此外,您的 IgnoreAllNonExisting 应由 CreateMap 调用中的 MemberList.Source 选项取代。这就是说“使用源类型作为我要验证的成员列表而不是目标类型”。

    【讨论】:

    • 能否请您评论一下我现有的解决方案以及改进和性能影响的潜在可能性。
    • 我不知道。我只知道您的原始配置文件不允许每个映射引擎实例隔离它们。我就是这么回答的。
    • 我调用的是 Mapper.CreateMap 而不是 this.CreateMap 所以它使用 Mapper 单例而不是 Autofac 创建的单例进行配置。这个答案帮助了我。
    【解决方案3】:

    我最终创建了一个映射器实例工厂,如下所示:

    using AutoMapper;
    using AutoMapper.Mappers;
    using System.Collections.Generic;
    
    public class MapperFactory<TSource,TDestination> where TSource : new() where TDestination : new()
    {
        private readonly ConfigurationStore _config;
    
        public MapperFactory(IEnumerable<Profile> profiles)
        {
            var platformSpecificRegistry = AutoMapper.Internal.PlatformAdapter.Resolve<IPlatformSpecificMapperRegistry>();
    
            platformSpecificRegistry.Initialize();
    
            _config = new AutoMapper.ConfigurationStore(new TypeMapFactory(), AutoMapper.Mappers.MapperRegistry.Mappers);
    
            foreach (var profile in profiles)
            {
                _config.AddProfile(profile);
            }
        }
    
        public TDestination Map(TSource sourceItem)
        {
            using (var mappingEngine = new MappingEngine(_config))
            {
                return mappingEngine.Map<TSource, TDestination>(sourceItem);
            }             
        }
    }
    

    现在我的解决方案中可以包含类似于以下的代码:

            var profiles = new Profile[]
            {
                new ApiTestClassToTestClassMappingProfile1(),
                new ApiTestClassToTestClassMappingProfile2(),
                new ApiTestClassToTestClassMappingProfile3() 
            };
    
            var mapper = new MapperFactory<ApiTestClass, TestClass>(profiles);
    
            var mappedItem = mapper.Map(testClassInstance);
    

    以上代码最大限度地提高了配置文件类的可重用性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-01
      • 1970-01-01
      • 2010-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-27
      • 1970-01-01
      相关资源
      最近更新 更多