2010-04-16 17 views
17

¿Hay alguna manera de autoconfigurar Automapper para buscar todos los perfiles en el espacio de nombres/ensamblaje? Lo que me gustaría hacer es añadir perfiles de mapeo para AutoMapper de montaje que se indica filtrada por interfaz dada, algo así como los convenios de exploración en StructureMap:Cómo escanear y configurar automáticamente perfiles en 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);    
    } 

He intentado utilizar SelfConfigure pero no puedo encontrar ninguna documentación sobre cómo usarlo para filtrar los perfiles:

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

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

Otra cuestión es cómo puedo informar de todos los mapas/perfiles que ya está iniciado (algo así como ObjectFactory.WhatDoIHave() en StructureMap)?

Respuesta

31

me encontré con este post mientras busca también, pero esta es la forma en que he implementado un esquema de asignación automática:

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

Así que cuando mi aplicación se inicia, todo lo que llamada se

AutoMapperConfiguration.Configure(); 

Y todos mis mapas están registrados.

+0

Esto parece ser mutuamente excluyente con el método 'ConstructServicesUsing'. Luchando con las dependencias que pasan atm. –

+0

Sí, no estoy pasando ninguna dependencia en mis mapas. Siempre puede registrarlos en un contenedor IoC y hacer que resuelva las dependencias por usted. Lo hubiéramos hecho, pero no había necesidad de eso. –

+2

Arnis L: simplemente cambie la configuración.AddProfile (Activator.CreateInstance (profile) as Profile); a configuration.AddProfile (ServiceLocator.Current.GetInstance (profile) as Profile); (o similar, obviamente, puede depender del contenedor de IoC que esté utilizando) para habilitar la inyección de dependencia. Gran respuesta. –

6

Sí, eso sería fantástico ... y es exactamente lo que estoy revisando para V2. Escaneo, registro, convenciones, etc.

No hay una buena función "¿Qué tengo?", Pero creo que definitivamente valdría la pena agregarla.

+0

Gracias por AutoMapper - Yo y muchos otros estaríamos perdidos sin eso. ¿Hay una publicación en el blog (o una publicación del hilo/artículo/SO del correo electrónico) sobre cómo 'Profile' y sus amigos deberían usarse allí de lo que usted está enterado? En este momento en SO, las cosas son un poco confusas ya que hay muchos ejemplos de la era v1 pero cosas anteriores de v2. Incluso una sentencia de una oración como 'manipule su DI para que recoja IXXXInitializar impls, y para que esos sean alimentados al ctor de XXXConfiguration y luego tenga, por ejemplo, Controladores que requieren mapeadores vinculados a IMapper que implementa IConfiguration 'o algo de ese tipo. –

1

Lo tengo así, no sé si es la mejor manera, pero funciona muy bien en proyectos bastante grandes.

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

Con esto, creo que no se puede controlar el ciclo de vida de las dependencias de perfil. –

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

En las últimas versiones de AutoMapper que es posible registrar múltiples Perfil de exploración uno o más conjuntos:.

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

Probado con AutoMapper v 6.0.2.0

Cuestiones relacionadas