Как сканировать и автоматически настраивать профили в AutoMapper?
есть ли способ автоматической настройки 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() in StructureMap)?
6 ответов
Я нашел этот пост во время поиска, но вот как я реализовал схему автоматического отображения:
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();
и все мои карты.Да, это было бы фантастическим...и именно то, что я ремонтирую для V2. Сканирование, Регистрация, конвенций и т. д.
нет хорошей функции "что у меня есть", но я думаю, что это определенно стоит добавить.
в последних версиях AutoMapper можно зарегистрировать несколько профиль сканирование одной или нескольких сборок:
Mapper.Initialize(x => x.AddProfiles(typeof(MyMappingProfile).Assembly));
протестировано с помощью AutoMapper V.6.0.2.0
У меня это так, не знаю, лучший ли это способ, но он очень хорошо работает на довольно большом проекте.
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);
}
}
}
}
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);
}
}
похоже на ответ @Martino, но с объектом MapperConfiguration. Это добавит все профили из сборки, содержащей тип MyProfile.
var config = new MapperConfiguration(cfg =>
{
cfg.AddProfiles(typeof(MyProfile));
});
var mapper = config.CreateMapper();