web-dev-qa-db-fra.com

Comment configurer Automapper dans ASP.NET Core

Je suis relativement nouveau chez .NET et j'ai décidé de m'attaquer à .NET Core plutôt que d'apprendre les «méthodes traditionnelles». J'ai trouvé un article détaillé sur la configuration d'AutoMapper pour .NET Core ici , mais existe-t-il une procédure plus simple pour un débutant?

154
theutz

Je l'ai compris! Voici les détails:

  1. Ajoutez le package AutoMapper principal à votre solution via NuGet .
  2. Ajoutez le package d'injection de dépendance AutoMapper à votre solution via NuGet .

  3. Créez une nouvelle classe pour un profil de mappage. (J'ai créé une classe dans le répertoire principal de la solution appelée MappingProfile.cs et ajouté le code suivant.) Je vais utiliser un objet User et UserDto comme exemple.

    public class MappingProfile : Profile {
        public MappingProfile() {
            // Add as many of these lines as you need to map your objects
            CreateMap<User, UserDto>();
            CreateMap<UserDto, User>();
        }
    }
    
  4. Puis ajoutez la configuration AutoMapperConfiguration dans le Startup.cs comme indiqué ci-dessous:

    public void ConfigureServices(IServiceCollection services) {
        // .... Ignore code before this
    
       // Auto Mapper Configurations
        var mappingConfig = new MapperConfiguration(mc =>
        {
            mc.AddProfile(new MappingProfile());
        });
    
        IMapper mapper = mappingConfig.CreateMapper();
        services.AddSingleton(mapper);
    
        services.AddMvc();
    
    }
    
  5. Pour appeler l'objet mappé dans le code, procédez comme suit:

    public class UserController : Controller {
    
        // Create a field to store the mapper object
        private readonly IMapper _mapper;
    
        // Assign the object in the constructor for dependency injection
        public UserController(IMapper mapper) {
            _mapper = mapper;
        }
    
        public async Task<IActionResult> Edit(string id) {
    
            // Instantiate source object
            // (Get it from the database or whatever your code calls for)
            var user = await _context.Users
                .SingleOrDefaultAsync(u => u.Id == id);
    
            // Instantiate the mapped data transfer object
            // using the mapper you stored in the private field.
            // The type of the source object is the first type argument
            // and the type of the destination is the second.
            // Pass the source object you just instantiated above
            // as the argument to the _mapper.Map<>() method.
            var model = _mapper.Map<UserDto>(user);
    
            // .... Do whatever you want after that!
        }
    }
    

J'espère que cela aide quelqu'un qui commence à zéro avec ASP.NET Core! J'apprécie tout commentaire ou critique car je suis encore novice dans le monde .NET!

391
theutz

la réponse de Theutz ici est très bonne, je veux juste ajouter ceci:

Si vous laissez votre profil de mappage hériter de MapperConfigurationExpression au lieu de Profile, vous pouvez très simplement ajouter un test pour vérifier votre configuration de mappage, ce qui est toujours pratique:

[Fact]
public void MappingProfile_VerifyMappings()
{
    var mappingProfile = new MappingProfile();

    var config = new MapperConfiguration(mappingProfile);
    var mapper = new Mapper(config);

    (mapper as IMapper).ConfigurationProvider.AssertConfigurationIsValid();
}
23
Arve Systad

Étape Pour utiliser AutoMapper avec ASP.NET Core.

Étape 1. Installation d'AutoMapper.Extensions.Microsoft.DependencyInjection à partir du package NuGet.

 enter image description here

Étape 2. Créez un dossier dans la solution pour conserver les mappages avec le nom "Mappings".

 enter image description here

Étape 3. Après avoir ajouté le dossier Mapping, nous avons ajouté une classe avec le nom "MappingProfile". Ce nom peut être unique et bien compris.

Dans cette classe, nous allons gérer tous les mappages. 

 enter image description here

Étape 4. Initialisation du mappeur au démarrage "ConfigureServices"

Dans la classe de démarrage, nous devons initialiser le profil que nous avons créé et également enregistrer le service AutoMapper.

  Mapper.Initialize(cfg => cfg.AddProfile<MappingProfile>());

  services.AddAutoMapper();

Extrait de code indiquant la méthode ConfigureServices où nous devons initialiser et enregistrer AutoMapper.

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }


    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<CookiePolicyOptions>(options =>
        {
            // This lambda determines whether user consent for non-essential cookies is needed for a given request.
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });


        // Start Registering and Initializing AutoMapper

        Mapper.Initialize(cfg => cfg.AddProfile<MappingProfile>());
        services.AddAutoMapper();

        // End Registering and Initializing AutoMapper

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    }}

Étape 5. Obtenir la sortie.

Pour obtenir le résultat obtenu, nous devons appeler AutoMapper.Mapper.Map et transmettre la destination et la source appropriées.

AutoMapper.Mapper.Map<Destination>(source);

Extrait de code

    [HttpPost]
    public void Post([FromBody] SchemeMasterViewModel schemeMaster)
    {
        if (ModelState.IsValid)
        {
            var mappedresult = AutoMapper.Mapper.Map<SchemeMaster>(schemeMaster);
        }
    }
10
Saineshwar

Je veux prolonger les réponses de @ theutz - à savoir cette ligne:

// services.AddAutoMapper(typeof(Startup));  // <-- newer automapper version uses this signature.

Il existe un bogue (probablement) dans AutoMapper.Extensions.Microsoft.DependencyInjection version 3.2.0. (J'utilise .NET Core 2.0)

Ceci est abordé dans this GitHub. Si vos classes héritant de la classe Profile d'AutoMapper existent en dehors de Assembly où votre classe de démarrage est, elles ne seront probablement pas enregistrées si votre injection AutoMapper ressemble à ceci:

services.AddAutoMapper();

sauf si vous spécifiez explicitement les assemblys dans lesquels rechercher les profils AutoMapper.

Cela peut être fait comme ça dans votre Startup.ConfigureServices:

services.AddAutoMapper(<assembies> or <type_in_assemblies>);

"assemblies" _ et "type_in_assemblies" pointent sur l'assembly où les classes de profil de votre application sont spécifiées. Par exemple:

services.AddAutoMapper(typeof(ProfileInOtherAssembly), typeof(ProfileInYetAnotherAssembly));

Je suppose (et je mets l'accent sur ce mot) en raison de la mise en œuvre suivante de la surcharge sans paramètre (code source depuis GitHub ):

public static IServiceCollection AddAutoMapper(this IServiceCollection services)
{
     return services.AddAutoMapper(null, AppDomain.CurrentDomain.GetAssemblies());
}

nous nous appuyons sur CLR ayant déjà un ensemble JITed contenant des profils AutoMapper qui peuvent être ou ne pas être vrais car ils sont uniquement jits si nécessaire (plus de détails dans this StackOverflow question).

10
GrayCat

J'utilise AutoMapper 6.1.1 et asp.net Core 1.1.2.

Tout d’abord, définissez les classes de profil héritées par Profile Class of Automapper. J'ai créé l'interface IProfile qui est vide, le seul but est de trouver les classes de ce type.

 public class UserProfile : Profile, IProfile
    {
        public UserProfile()
        {
            CreateMap<User, UserModel>();
            CreateMap<UserModel, User>();
        }
    }

Maintenant, créez une classe séparée, par ex. Mappages 

 public class Mappings
    {
     public static void RegisterMappings()
     {            
       var all =
       Assembly
          .GetEntryAssembly()
          .GetReferencedAssemblies()
          .Select(Assembly.Load)
          .SelectMany(x => x.DefinedTypes)
          .Where(type => typeof(IProfile).GetTypeInfo().IsAssignableFrom(type.AsType()));

            foreach (var ti in all)
            {
                var t = ti.AsType();
                if (t.Equals(typeof(IProfile)))
                {
                    Mapper.Initialize(cfg =>
                    {
                        cfg.AddProfiles(t); // Initialise each Profile classe
                    });
                }
            }         
        }

    }

Désormais, dans le projet Web principal de MVC dans le fichier Startup.cs, dans le constructeur, appelez la classe Mapping qui initialisera tous les mappages au moment de l'application.

Mappings.RegisterMappings();
5
Aamir

Je l'ai résolu de cette façon (comme ci-dessus mais j'ai l'impression que c'est une solution plus propre) pour .NET Core 2.2/Automapper 8.1.1 avec Extensions.DI 6.1.1.

Créez la classe MappingProfile.cs et remplissez le constructeur avec Maps (je prévois d'utiliser une seule classe pour contenir tous mes mappages)

    public class MappingProfile : Profile
    {
        public MappingProfile()
        {
            CreateMap<Source, Dest>().ReverseMap();
        }
    }

Dans Startup.cs, ajoutez ci-dessous pour ajouter à DI (l'argument Assembly est pour la classe qui contient vos configurations de mappage, dans mon cas, c'est la classe MappingProfile).

//add automapper DI
services.AddAutoMapper(typeof(MappingProfile));

Dans Controller, utilisez-le comme n'importe quel autre objet DI

    [Route("api/[controller]")]
    [ApiController]
    public class AnyController : ControllerBase
    {
        private readonly IMapper _mapper;

        public AnyController(IMapper mapper)
        {
            _mapper = mapper;
        }

        public IActionResult Get(int id)
        {
            var entity = repository.Get(id);
            var dto = _mapper.Map<Dest>(entity);

            return Ok(dto);
        }
    }


4
Coy Meeks

services.AddAutoMapper (); n'a pas fonctionné pour moi. (J'utilise Asp.Net Core 2.0)

Après avoir configuré comme ci-dessous

   var config = new AutoMapper.MapperConfiguration(cfg =>
   {                 
       cfg.CreateMap<ClientCustomer, Models.Customer>();
   });

initialiser le mappeur IMapper mapper = config.CreateMapper ();

et ajoutez l'objet mappeur aux services en tant que singleton services.AddSingleton (mappeur);

de cette façon, je peux ajouter une DI au contrôleur

  private IMapper autoMapper = null;

  public VerifyController(IMapper mapper)
  {              
   autoMapper = mapper;  
  }

et j'ai utilisé comme ci-dessous dans mes méthodes d'action

  ClientCustomer customerObj = autoMapper.Map<ClientCustomer>(customer);
2
Venkat pv

Pour ASP.NET Core, les éléments suivants proviennent directement d’Automapper et d’une ligne dans votre classe de démarrage: https://github.com/AutoMapper/AutoMapper.Extensions.Microsoft.DependencyInjection/blob/master/README. md

Ajoutez simplement quelques classes de profil. Ajoutez ensuite ci-dessous à votre classe startup.cs .services.AddAutoMapper(OneOfYourProfileClassNamesHereSoItCanFindYourProfileAssembly)

Ensuite, il vous suffit d’injecter IMapper dans vos contrôleurs ou partout où vous en avez besoin:

public class EmployeesController {

    private readonly IMapper _mapper;

    public EmployeesController(IMapper mapper){

        _mapper = mapper;
    }

Et si vous voulez utiliser ProjectTo c'est maintenant simplement:

var customers = await dbContext.Customers.ProjectTo<CustomerDto>(_mapper.ConfigurationProvider).ToListAsync()
1
user1191559

à propos de theutz answer, il n’est pas nécessaire de spécifier le IMapper mapper parrameter au niveau du constructeur de l’automate.

vous pouvez utiliser le mappeur car il s'agit d'un membre statique à n'importe quel endroit du code.

public class UserController : Controller {
   public someMethod()
   {
      Mapper.Map<User, UserDto>(user);
   }
}
0
yaronmil

Pour ajouter à ce qu'Arve Systad a mentionné pour les tests. Si, pour une raison quelconque, vous êtes comme moi et souhaitez conserver la structure d'héritage fournie dans la solution theutz, vous pouvez configurer MapperConfiguration de la manière suivante:

var mappingProfile = new MappingProfile();
var config = new MapperConfiguration(cfg =>
{
    cfg.AddProfile(mappingProfile);
});
var mapper = new Mapper(config);

Je l'ai fait dans NUnit.

0
LandSharks

Dans mon Startup.cs (Core 2.2, Automapper 8.1.1)

services.AddAutoMapper(new Type[] { typeof(DAL.MapperProfile) });            

Dans mon projet d'accès aux données

namespace DAL
{
    public class MapperProfile : Profile
    {
        // place holder for AddAutoMapper (to bring in the DAL Assembly)
    }
}

Dans ma définition de modèle

namespace DAL.Models
{
    public class PositionProfile : Profile
    {
        public PositionProfile()
        {
            CreateMap<Position, PositionDto_v1>();
        }
    }

    public class Position
    {
        ...
    }
0
Brian Rice

J'ai trouvé automapper difficile à démarrer. Quand je ne pouvais pas l'injecter dans le constructeur de ma classe Test, je l'ai complètement abandonné. J'utiliserai plutôt ModelBindings pour les propriétés non modifiables et les classes de transfert de données pour les propriétés devant être masquées et gérer le mappage moi-même.

0
Metonymy