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?
Je l'ai compris! Voici les détails:
Ajoutez le package d'injection de dépendance AutoMapper à votre solution via NuGet .
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>();
}
}
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();
}
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!
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();
}
Étape Pour utiliser AutoMapper avec ASP.NET Core.
Étape 1. Installation d'AutoMapper.Extensions.Microsoft.DependencyInjection à partir du package NuGet.
Étape 2. Créez un dossier dans la solution pour conserver les mappages avec le nom "Mappings".
É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.
É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);
}
}
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>);
où "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).
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();
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);
}
}
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);
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()
à 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);
}
}
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.
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
{
...
}
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.