Как сканировать и настраивать профили в AutoMapper?

18

Есть ли способ автонастройки Automapper для сканирования всех профилей в пространстве имен / сборке? То, что я хотел бы сделать, это добавить профили сопоставления в AutoMapper из данной сборки, отфильтрованной данным интерфейсом, что-то вроде соглашений об обнаружении в StructureMap:

    public static void Configure()
    {
        ObjectFactory.Initialize(x =>
            {
                // Scan Assembly
                x.Scan(
                    scanner =>
                    {
                        scanner.TheCallingAssembly();
                        scanner.Convention<MyCustomConvention>();
                        scanner.WithDefaultConventions();
                    });

                // Add Registries
                x.AddRegistry(new SomeRegistry());
            });

        Debug.WriteLine(ObjectFactory.WhatDoIHave());
    }

public class MyCustomConvention : IRegistrationConvention
{
    public void Process(Type type, Registry registry)
    {
        if (!type.CanBeCastTo(typeof(IMyType)))
        {
            return;
        }

        string name = type.Name.Replace("SomeRubishName", String.Empty);
        registry.AddType(typeof(IMyType), type, name);            
    }

Я попытался использовать SelfConfigure, но не могу найти документацию о том, как использовать его для фильтрации профилей:

    public static void Configure()
    {
        Mapper.Initialize(x =>
                              {
                                  // My Custom profile
                                  x.AddProfile<MyMappingProfile>();

                                  // Scan Assembly
                                  x.SelfConfigure(Assembly.GetCallingAssembly());
                              });
    }

Другой вопрос: как я могу сообщить обо всех уже инициализированных картах / профилях (что-то вроде ObjectFactory.WhatDoIHave () в StructureMap)?

    
задан Wojciech Markowski 16.04.2010 в 10:34
источник

5 ответов

32

Я тоже нашел этот пост при поиске, но именно так я реализовал схему автоматического сопоставления:

public class MyCustomMap : Profile
{
    protected override void Configure()
    {
        CreateMap<MyCustomViewModel, MyCustomObject>()
            .ForMember(dest => dest.Phone,
                        opt => opt.MapFrom(
                        src => src.PhoneAreaCode + src.PhoneFirstThree + src.PhoneLastFour));
    }
}

public static class AutoMapperConfiguration
{
    public static void Configure()
    {
        Mapper.Initialize(x => GetConfiguration(Mapper.Configuration));
    }

    private static void GetConfiguration(IConfiguration configuration)
    {
        var profiles = typeof(MyCustomMap).Assembly.GetTypes().Where(x => typeof(Profile).IsAssignableFrom(x));
        foreach (var profile in profiles)
        {
            configuration.AddProfile(Activator.CreateInstance(profile) as Profile);
        }
    }
}

Итак, когда мое приложение запускается, все, что я вызываю, это

AutoMapperConfiguration.Configure(); 

И все мои карты зарегистрированы.

    
ответ дан Jason More 01.09.2010 в 15:11
  • Это кажется взаимоисключающим с методом «ConstructServicesUsing». Борьба с проходящими зависимостями атм. –  Arnis Lapsa 05.10.2010 в 13:37
  • Да, я не передаю никаких зависимостей на своих картах. Вы всегда можете зарегистрировать их в контейнере IoC и разрешить им зависимости. Мы бы это сделали, но в этом не было необходимости. –  Jason More 05.10.2010 в 15:04
  • Arnis L - просто измените конфигурацию .AddProfile (Activator.CreateInstance (profile) as Profile); to configuration.AddProfile (ServiceLocator.Current.GetInstance (профиль) как профиль); (или аналогичные, очевидно, это может зависеть от того, какой контейнер IoC вы используете), чтобы включить инъекцию зависимостей. Отличный ответ. –  Paul Suart 21.10.2010 в 10:11
7

Да, это было бы фантастически ... и именно то, что я перестраиваю для V2. Сканирование, регистрация, соглашения и т. Д.

Нет хорошей функции «Что у меня есть», но я думаю, что это определенно стоит добавить.

    
ответ дан Jimmy Bogard 16.04.2010 в 14:47
  • Спасибо за AutoMapper - я и многие другие будут потеряны без него. Есть ли сообщение в блоге (или по электронной почте thread / article / SO post) о том, как профиль и друзья должны использоваться там, о которых вы знаете? Прямо сейчас на SO, все немного запутанно, так как есть много примеров эпохи v1, но предыдущие немного v2. Даже одно предложение, такое как «подстроить ваш DI, чтобы забрать IXXXInitialize impls, и для тех, кто будет подаваться на ctor XXXConfiguration, а затем, например, Контроллеры, требующие отображения карт, привязанных к IMapper, которые реализуются IConfiguration 'или что-то вроде этого. –  Ruben Bartelink 12.06.2012 в 09:08
6

В последних версиях AutoMapper можно зарегистрировать несколько Profile для сканирования одной или нескольких сборок:

 Mapper.Initialize(x => x.AddProfiles(typeof(MyMappingProfile).Assembly));

Протестировано с помощью AutoMapper v. 6.0.2.0

    
ответ дан Martino Bordin 06.05.2017 в 18:32
1

У меня это так, не знаю, лучший ли это, но он очень хорошо работает на довольно большом проекте.

public class AutoMapperGlobalConfiguration : IGlobalConfiguration
    {
        private AutoMapper.IConfiguration _configuration;

        public AutoMapperGlobalConfiguration(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        public void Configure()
        {
            //add all defined profiles
            var query = this.GetType().Assembly.GetExportedTypes()
                .Where(x => x.CanBeCastTo(typeof(AutoMapper.Profile)));

            _configuration.RecognizePostfixes("Id");

            foreach (Type type in query)
            {
                _configuration.AddProfile(ObjectFactory.GetInstance(type).As<Profile>());
            }

            //create maps for all Id2Entity converters
            MapAllEntities(_configuration);

           Mapper.AssertConfigurationIsValid();
        }

        private static void MapAllEntities(IProfileExpression configuration)
        {
            //get all types from the SR.Domain assembly and create maps that
            //convert int -> instance of the type using Id2EntityConverter
            var openType = typeof(Id2EntityConverter<>);
            var idType = typeof(int);
            var persistentEntties = typeof(SR.Domain.Policy.Entities.Bid).Assembly.GetTypes()
               .Where(t => typeof(EntityBase).IsAssignableFrom(t))
               .Select(t => new
               {
                   EntityType = t,
                   ConverterType = openType.MakeGenericType(t)
               });
            foreach (var e in persistentEntties)
            {
                var map = configuration.CreateMap(idType, e.EntityType);
                map.ConvertUsing(e.ConverterType);
            }
        }
    }
}
    
ответ дан epitka 20.04.2010 в 21:07
  • С этим - я думаю, вы не можете контролировать жизненный цикл зависимостей профиля. –  Arnis Lapsa 05.10.2010 в 13:50
0
 public class AutoMapperAdapter : IMapper
{
    private readonly MapperConfigurationExpression _configurationExpression =
        new MapperConfigurationExpression();

    public void AssertConfigurationIsValid() { Mapper.AssertConfigurationIsValid(); }

    public void CreateMap<TSource, TDestination>()
    {
        _configurationExpression.CreateMap<TSource, TDestination>();
    }

    public void Initialize() { Mapper.Initialize(_configurationExpression); }

    public TDestination Map<TDestination>(object source)
    {
        return Mapper.Map<TDestination>(source);
    }
}
    
ответ дан user3472484 12.10.2016 в 08:43