214 votes

Où placer les AutoMapper.CreateMaps ?

Je suis à l'aide d' AutoMapper en ASP.NET MVC application. On m'a dit que je devrais aller l' AutoMapper.CreateMap ailleurs comme ils ont beaucoup de frais généraux. Je ne sais pas trop comment faire pour la conception de ma demande de mettre ces appels en seulement 1 place.

J'ai une couche web, le service de la couche et une couche de données. Chaque projet qui lui est propre. J'utilise Ninject DI tout. Je vais utiliser AutoMapper à la fois sur internet et les couches de service.

Alors, quels sont vos réglages pour AutoMappers'CreateMap? Où avez-vous le mettre? Comment appelez-vous cela?

219voto

RPM1984 Points 39648

N'a pas d'importance, aussi longtemps que c'est une classe statique. Il est tout au sujet de la convention.

Notre convention est que chaque "couche" (web, des services, des données) est un fichier unique appelé AutoMapperXConfiguration.cs, avec une seule méthode appelée Configure()X est la couche.

L' Configure() méthode appelle alors private méthodes pour chaque zone.

Voici un exemple de notre niveau web de la config:

public static class AutoMapperWebConfiguration
{
   public static void Configure()
   {
      ConfigureUserMapping();
      ConfigurePostMapping();
   }

   private static void ConfigureUserMapping()
   {
      Mapper.CreateMap<User,UserViewModel>();
   } 

   // ... etc
}

Nous avons créer une méthode pour chaque "globale" (Utilisateur, Post), donc les choses sont bien séparés.

Ensuite, votre Global.asax:

AutoMapperWebConfiguration.Configure();
AutoMapperServicesConfiguration.Configure();
AutoMapperDomainConfiguration.Configure();
// etc

C'est un peu comme une "interface de mots" - ne peut pas l'appliquer, mais vous vous y attendez, de sorte que vous pouvez de code (et refactoriser) si nécessaire.

EDIT:

Juste pensé que je devais mentionner que j'utilise désormais AutoMapper profils, de sorte que l'exemple ci-dessus devient:

public static class AutoMapperWebConfiguration
{
   public static void Configure()
   {
      Mapper.Initialize(cfg =>
      {
        cfg.AddProfile(new UserProfile());
        cfg.AddProfile(new PostProfile());
      });
   }
}

public class UserProfile : Profile
{
    protected override void Configure()
    {
         Mapper.CreateMap<User,UserViewModel>();
    }
}

Beaucoup plus propres et plus robuste.

33voto

Brett Allred Points 1993

Vous pouvez vraiment mettre n'importe où aussi longtemps que votre projet web des références à l'assemblée qu'il est. Dans votre situation, je voudrais le mettre dans la couche de service que qui sera accessible par le web et la couche de la couche de service et, plus tard, si vous décidez de faire une application console ou que vous faites une unité de projet de test de la configuration de mappage sera disponible à partir de ces projets ainsi.

Dans votre Global.asax vous appelle ensuite la méthode qui définit l'ensemble de vos cartes. Voir ci-dessous:

Fichier AutoMapperBootStrapper.cs

public static class AutoMapperBootStrapper
{
     public static void BootStrap()
     {  
         AutoMapper.CreateMap<Object1, Object2>();
         // So on...


     }
}

Mondiale.asax au lancement de l'application

appelez simplement

AutoMapperBootStrapper.BootStrap();

Maintenant, certaines personnes font valoir contre cette méthode est contraire à certains principes SOLIDES, qu'ils ont des arguments valables. Ici, ils sont pour la lecture.

La configuration de Automapper dans le programme d'Amorçage viole Ouvert-Fermé le Principe?

16voto

codeprogression Points 1563

Je voudrais prendre une approche similaire comme Thoai. Mais je voudrais utiliser le haut- SelfProfiler<> classe permettant de gérer les cartes, puis utilisez l' Mapper.SelfConfigure fonction pour initialiser.

À l'aide de cet objet en tant que source de:

public class User
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDate { get; set; }
    public string GetFullName()
    {
        return string.Format("{0} {1}", FirstName, LastName);
    }
}

Et comme la destination:

public class UserViewModel
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class UserWithAgeViewModel
{
    public int Id { get; set; }
    public string FullName { get; set; }
    public int Age { get; set; }
}

Vous pouvez créer ces profils:

public class UserViewModelProfile : SelfProfiler<User,UserViewModel>
{
    protected override void DescribeConfiguration(IMappingExpression<User, UserViewModel> map)
    {
    //This maps by convention, so no configuration needed
    }
}

public class UserWithAgeViewModelProfile : SelfProfiler<User, UserWithAgeViewModel>
{
    protected override void DescribeConfiguration(IMappingExpression<User, UserWithAgeViewModel> map)
    {
    //This map needs a little configuration
        map.ForMember(d => d.Age, o => o.MapFrom(s => DateTime.Now.Year - s.BirthDate.Year));
    }
}

Pour initialiser dans votre application, créez cette classe

 public class AutoMapperConfiguration
 {
      public static void Initialize()
      {
          Mapper.Initialize(x=>
          {
              x.SelfConfigure(typeof (UserViewModel).Assembly);
              // add assemblies as necessary
          });
      }
 }

Ajoutez cette ligne à votre global.asax.cs fichier: AutoMapperConfiguration.Initialize()

Maintenant, vous pouvez placer votre mapping des classes où ils font sens pour vous, et ne pas s'inquiéter d'un monolithique de mappage de classe.

15voto

Marius Points 3003

Pour ceux d'entre vous qui respectent les conditions suivantes:

1) à l'aide d'un conteneur ioc
2) n'aime pas à ouvrir fermé pour cette
3) n'aime pas constitué d'un seul fichier de config

J'ai fait un combo entre les profils et les tirant parti de mon conteneur ioc:

  • cio de configuration

    public class Automapper : IWindsorInstaller
    {
    
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Classes.FromThisAssembly().BasedOn<Profile>().WithServiceBase());
    
        container.Register(Component.For<IMappingEngine>().UsingFactoryMethod(k =>
        {
            Profile[] profiles = k.ResolveAll<Profile>();
    
            Mapper.Initialize(cfg =>
            {
                foreach (var profile in profiles)
                {
                    cfg.AddProfile(profile);
                }
            });
    
            profiles.ForEach(k.ReleaseComponent);
    
            return Mapper.Engine;
        }));
    }
    

    }

  • Configuraton exemple

    public class TagStatusViewModelMappings : Profile
    {
        protected override void Configure()
        {
            Mapper.CreateMap<Service.Contracts.TagStatusViewModel, TagStatusViewModel>();
        }
    }
    
  • Exemple d'utilisation

    public class TagStatusController : ApiController
    {
        private readonly IFooService _service;
        private readonly IMappingEngine _mapper;
    
        public TagStatusController(IFooService service, IMappingEngine mapper)
        {
            _service = service;
            _mapper = mapper;
        }
    
        [Route("")]
        public HttpResponseMessage Get()
        {
            var response = _service.GetTagStatus();
    
            return Request.CreateResponse(HttpStatusCode.Accepted, _mapper.Map<List<ViewModels.TagStatusViewModel>>(response)); 
        }
    }
    

Le compromis est que vous avez à référence le Mappeur par le IMappingEngine interface au lieu de la statique Mappeur, mais c'est une convention que je peux vivre avec.

14voto

Javad_Amiry Points 9003

Tous des solutions ci-dessus fournissent une méthode statique d'appel (à partir de app_start ou n'importe où) qu'il devrait en appeler d'autres méthodes pour configurer des parties de la cartographie de configuration. Mais, si vous avez une application modulaire, les modules peuvent plug in et hors de l'application à tout moment, ces solutions ne fonctionne pas. Je suggère d'utiliser WebActivator bibliothèque qui peut enregistrer certaines méthodes pour exécuter sur app_pre_start et app_post_start n'importe où:

// in MyModule1.dll
public class InitMapInModule1 {
    static void Init() {
        Mapper.CreateMap<User, UserViewModel>();
        // other stuffs
    }
}
[assembly: PreApplicationStartMethod(typeof(InitMapInModule1), "Init")]

// in MyModule2.dll
public class InitMapInModule2 {
    static void Init() {
        Mapper.CreateMap<Blog, BlogViewModel>();
        // other stuffs
    }
}
[assembly: PreApplicationStartMethod(typeof(InitMapInModule2), "Init")]

// in MyModule3.dll
public class InitMapInModule3 {
    static void Init() {
        Mapper.CreateMap<Comment, CommentViewModel>();
        // other stuffs
    }
}
[assembly: PreApplicationStartMethod(typeof(InitMapInModule2), "Init")]

// and in other libraries...

Vous pouvez installer WebActivator via NuGet. Aussi, ici et ici, j'ai créer certains blog-posts-persan - sur WebActivator bibliothèque, vous pouvez voir des exemples de code. Ce qui concerne.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X