2010-04-16 6 views
17

Czy istnieje sposób automatycznej konfiguracji programu Automapper do skanowania wszystkich profili w przestrzeni nazw/złożeniu? Co chciałbym zrobić, to dodać profile mapowania do AutoMapper z danego zespołu przefiltrowanej przez dany interfejs, coś jak konwencje skanowania w StructureMap:Jak skanować i automatycznie konfigurować profile w AutoMapper?

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);    
    } 

Próbowałem użyć SelfConfigure ale nie może znaleźć żadnej dokumentacji na jak go używać, aby odfiltrować profili:

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

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

Inną kwestią jest to w jaki sposób mogę zgłosić wszystkie mapy/profile już zainicjowany (coś jak ObjectFactory.WhatDoIHave() w StructureMap)?

Odpowiedz

31

znalazłem ten artykuł podczas poszukiwania, jak również, ale to jest jak ja wdrożony system automatycznego mapowania:

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); 
     } 
    } 
} 

Więc kiedy zaczyna mój wniosek, wszystko co wywołanie jest

AutoMapperConfiguration.Configure(); 

Wszystkie moje mapy są zarejestrowane.

+0

Wydaje się, że wyklucza się to wzajemnie za pomocą metody "ConstructServicesUsing". Zmaganie z przekazywaniem zależności atm. –

+0

Tak, nie przekazuję żadnych zależności na moich mapach. Zawsze możesz zarejestrować je w kontenerze IoC i sprawić, że rozwiąże ono dla ciebie zależności. Zrobilibyśmy to, ale nie było takiej potrzeby. –

+2

Arnis L - wystarczy zmienić configuration.AddProfile (Activator.CreateInstance (profile) jako Profile); do configuration.AddProfile (ServiceLocator.Current.GetInstance (profile) jako Profile); (lub podobnie, oczywiście może to zależeć od tego, którego kontenera IoC używasz), aby umożliwić wstrzyknięcie zależności. Świetna odpowiedź. –

6

Tak, to byłoby fantastyczne ... i dokładnie to, co robię przegląd dla V2. Skanowanie, rejestracja, konwencje itp.

Nie ma dobrej funkcji "Co mam", ale myślę, że zdecydowanie warto ją było dodać.

+0

Dzięki za AutoMapper - Bez niego ja i wielu innych zginiemy. Czy jest wpis na blogu (lub wątek e-mail/artykuł/wpis SO) o tym, jak należy rozumieć "Profil" i znajomych? W tej chwili na SO, rzeczy są nieco mylące, ponieważ istnieje wiele przykładów z V1 era, ale poprzednie małe rzeczy v2. Nawet jedno zdanie typu "rig your DI, aby odebrać IXXXInitialize implikuje, i dla tych, które mają być dostarczane do ctor XXXConfiguration, a następnie mieć np. Kontrolery wymagające zmapowanych przez programatorów map do IMapper, które są implementowane przez IConfiguration lub coś w tym stylu. –

1

Mam to tak, nie wiem, czy to jest najlepszy sposób, ale działa bardzo dobrze na dość duży projekt.

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); 
      } 
     } 
    } 
} 
+0

Dzięki temu - myślę, że nie można kontrolować cyklu życia zależności profilu. –

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); 
    } 
} 
5

W najnowszych wersjach AutoMapper to możliwe, aby zarejestrować kilka Profil odwiedzony skanowania jednego lub więcej zespołów.

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

Testowane z AutoMapper v 6.0.2.0