2010-04-16 6 views
17

Existe-t-il un moyen d'auto-configurer Automapper pour analyser tous les profils dans l'espace de noms/l'assemblage? Ce que je voudrais faire est d'ajouter des profils de cartographie à AutoMapper de l'assemblage donné filtré par interface donnée, quelque chose comme les conventions d'analyse dans StructureMap:Comment numériser et configurer automatiquement des profils dans 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);    
    } 

J'ai essayé d'utiliser SelfConfigure mais ne trouve aucune documentation sur comment l'utiliser pour filtrer les profils:

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

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

Une autre question est de savoir comment puis-je signaler toutes les cartes/profils déjà initialisés (quelque chose comme ObjectFactory.WhatDoIHave() dans StructureMap)?

Répondre

31

Je trouve ce poste lors de la recherche aussi bien, mais voilà comment je mis en place un système de cartographie automatique:

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

Alors, quand ma demande commence, tout ce que j'appelle est

AutoMapperConfiguration.Configure(); 

Et toutes mes cartes sont enregistrées.

+0

Cela semble être mutuellement exclusif avec la méthode 'ConstructServicesUsing'. Luttant avec dépassement des dépendances atm. –

+0

Oui, je ne passe pas de dépendances dans mes cartes. Vous pouvez toujours les enregistrer dans un conteneur IoC et le faire résoudre les dépendances pour vous. Nous aurions fait cela mais il n'y en avait pas besoin. –

+2

Arnis L - il suffit de modifier configuration.AddProfile (Activator.CreateInstance (profil) en tant que profil); à configuration.AddProfile (ServiceLocator.Current.GetInstance (profile) en tant que Profile); (ou similaire, évidemment, cela dépend du conteneur IoC que vous utilisez) pour permettre l'injection de dépendances. Très bonne réponse. –

6

Oui, ce serait fantastique ... et exactement ce que je suis en train de réviser pour V2. Numérisation, enregistrement, conventions, etc.

Il n'y a pas une bonne fonctionnalité "Qu'est-ce que j'ai?", Mais je pense que cela vaudrait certainement la peine d'ajouter.

+0

Merci pour AutoMapper - Moi et beaucoup d'autres seraient perdus sans ça. Existe-t-il un article de blog (ou un fil de discussion/un article/un message sur l'article) sur la façon dont 'Profile' et les amis devraient être utilisés là-bas dont vous avez connaissance? À l'heure actuelle sur SO, les choses sont un peu confuses car il y a beaucoup d'exemples de la v1 ère, mais les petites choses précédentes v2. Même une chose en une phrase comme 'rig votre DI pour ramasser IXXXInitialize impls, et pour ceux qui doivent être nourris au ctor de XXXConfiguration, puis avoir par exemple. Contrôleurs nécessitant des mappeurs liés à IMapper qui est implémenté par IConfiguration 'ou quelque chose de ce genre. –

1

Je l'ai comme ça, je ne sais pas si c'est la meilleure façon, mais cela fonctionne très bien sur un très gros projet.

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

Avec cela - Je pense que vous ne pouvez pas contrôler le cycle de vie des dépendances de profil. –

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

Dans les dernières versions de AutoMapper il est possible d'enregistrer plusieurs Profil la numérisation d'un ou plusieurs ensembles:.

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

Testé avec AutoMapper v 6.0.2.0

Questions connexes