Soy relativamente nuevo en .NET, y decidí abordar .NET Core en lugar de aprender las "viejas formas". Encontré un artículo detallado sobre cómo configurar AutoMapper para .NET Core aquí , pero ¿hay un tutorial más simple para un novato?
Soy relativamente nuevo en .NET, y decidí abordar .NET Core en lugar de aprender las "viejas formas". Encontré un artículo detallado sobre cómo configurar AutoMapper para .NET Core aquí , pero ¿hay un tutorial más simple para un novato?
Respuestas:
¡Me lo imaginé! Aquí están los detalles:
Agregue el paquete de inyección de dependencia de AutoMapper a su solución a través de NuGet .
Cree una nueva clase para un perfil de mapeo. (Hice una clase en el directorio principal de la solución llamada MappingProfile.cs
y agregué el siguiente código). Usaré un objeto User
y UserDto
como ejemplo.
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>();
}
}
Luego agregue la AutoMapperConfiguration en el Startup.cs
que se muestra a continuación:
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();
}
Para invocar el objeto mapeado en código, haga algo como lo siguiente:
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!
}
}
¡Espero que esto ayude a alguien que comienza de cero con ASP.NET Core! Agradezco cualquier comentario o crítica ya que todavía soy nuevo en el mundo .NET.
Profile
se ubican las clases
Paso para usar AutoMapper con ASP.NET Core.
Paso 1. Instalar AutoMapper.Extensions.Microsoft.DependencyInjection desde el paquete NuGet.
Paso 2. Cree una carpeta en solución para mantener las asignaciones con el nombre "Asignaciones".
Paso 3. Después de agregar la carpeta Mapping, hemos agregado una clase con el nombre " MappingProfile ". Este nombre puede ser único y bueno de entender.
En esta clase, vamos a mantener todas las asignaciones.
Paso 4. Inicializando Mapper en el inicio "ConfigureServices"
En Startup Class, necesitamos inicializar el perfil que hemos creado y también registrar el servicio AutoMapper.
Mapper.Initialize(cfg => cfg.AddProfile<MappingProfile>());
services.AddAutoMapper();
Fragmento de código para mostrar el método ConfigureServices donde necesitamos inicializar y registrar 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);
}}
Paso 5. Obtener salida.
Para obtener el resultado del mapeo, debemos llamar a AutoMapper.Mapper.Map y pasar el Destino y el Origen adecuados.
AutoMapper.Mapper.Map<Destination>(source);
Fragmento de código
[HttpPost]
public void Post([FromBody] SchemeMasterViewModel schemeMaster)
{
if (ModelState.IsValid)
{
var mappedresult = AutoMapper.Mapper.Map<SchemeMaster>(schemeMaster);
}
}
'Mapper' does not contain a definition for 'initialize'
. Estoy usando la AutoMapper.Extensions.Microsoft.DependencyInjection
versión 7.0.0
Quiero extender las respuestas de @ theutz, es decir, esta línea:
// services.AddAutoMapper(typeof(Startup)); // <-- newer automapper version uses this signature.
Hay un error ( probablemente ) en AutoMapper.Extensions.Microsoft.DependencyInjection versión 3.2.0. (Estoy usando .NET Core 2.0)
Esto se aborda en este problema de GitHub. Si sus clases que heredan la clase Perfil de AutoMapper existen fuera del ensamblaje donde está su clase de Inicio, probablemente no se registrarán si su inyección de AutoMapper se ve así:
services.AddAutoMapper();
a menos que especifique explícitamente qué ensamblajes buscar en los perfiles de AutoMapper.
Se puede hacer así en su Startup.ConfigureServices:
services.AddAutoMapper(<assembies> or <type_in_assemblies>);
donde "ensamblados" y "type_in_assemblies" apuntan al ensamblado donde se especifican las clases de perfil en su aplicación. P.ej:
services.AddAutoMapper(typeof(ProfileInOtherAssembly), typeof(ProfileInYetAnotherAssembly));
Yo supongo (y pongo énfasis en esta palabra) que, debido a raíz de la aplicación de la sobrecarga sin parámetros (código fuente desde GitHub ):
public static IServiceCollection AddAutoMapper(this IServiceCollection services)
{
return services.AddAutoMapper(null, AppDomain.CurrentDomain.GetAssemblies());
}
confiamos en que CLR ya ha ensamblado JIT que contiene perfiles de AutoMapper que pueden ser o no ciertos, ya que solo se modifican cuando es necesario (más detalles en esta pregunta de StackOverflow).
La respuesta de theutz aquí es muy buena, solo quiero agregar esto:
Si deja que su perfil de mapeo herede en MapperConfigurationExpression
lugar de Profile
, simplemente puede agregar una prueba para verificar su configuración de mapeo, que siempre es útil:
[Fact]
public void MappingProfile_VerifyMappings()
{
var mappingProfile = new MappingProfile();
var config = new MapperConfiguration(mappingProfile);
var mapper = new Mapper(config);
(mapper as IMapper).ConfigurationProvider.AssertConfigurationIsValid();
}
Lo resolví de esta manera (similar a lo anterior pero siento que es una solución más limpia) para .NET Core 2.2 / Automapper 8.1.1 w / Extensions.DI 6.1.1.
Crear la clase MappingProfile.cs y completar el constructor con Maps (planeo usar una sola clase para contener todas mis asignaciones)
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<Source, Dest>().ReverseMap();
}
}
En Startup.cs, agregue a continuación para agregar a DI (el argumento de ensamblaje es para la clase que contiene sus configuraciones de mapeo, en mi caso, es la clase MappingProfile).
//add automapper DI
services.AddAutoMapper(typeof(MappingProfile));
En Controller, úselo como lo haría con cualquier otro objeto 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);
}
}
MappingProfiles
con lo new Type[]{}
que se muestra en esta respuesta .
En mi Startup.cs (Core 2.2, Automapper 8.1.1)
services.AddAutoMapper(new Type[] { typeof(DAL.MapperProfile) });
En mi proyecto de acceso a datos
namespace DAL
{
public class MapperProfile : Profile
{
// place holder for AddAutoMapper (to bring in the DAL assembly)
}
}
En mi definición de modelo
namespace DAL.Models
{
public class PositionProfile : Profile
{
public PositionProfile()
{
CreateMap<Position, PositionDto_v1>();
}
}
public class Position
{
...
}
services.AddAutoMapper( typeof(DAL.MapperProfile) );
lugar de services.AddAutoMapper(new Type[] { typeof(DAL.MapperProfile) });
?
Me gustan muchas respuestas, particularmente la de @saineshwar. Estoy usando .net Core 3.0 con AutoMapper 9.0, así que siento que es hora de actualizar su respuesta.
Lo que funcionó para mí fue en Startup.ConfigureServices (...) registre el servicio de esta manera:
services.AddAutoMapper(cfg => cfg.AddProfile<MappingProfile>(),
AppDomain.CurrentDomain.GetAssemblies());
Creo que el resto de la respuesta de @saineshwar se mantiene perfecta. Pero si alguien está interesado, mi código de controlador es:
[HttpGet("{id}")]
public async Task<ActionResult> GetIic(int id)
{
// _context is a DB provider
var Iic = await _context.Find(id).ConfigureAwait(false);
if (Iic == null)
{
return NotFound();
}
var map = _mapper.Map<IicVM>(Iic);
return Ok(map);
}
Y mi clase de mapeo:
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<Iic, IicVM>()
.ForMember(dest => dest.DepartmentName, o => o.MapFrom(src => src.Department.Name))
.ForMember(dest => dest.PortfolioTypeName, o => o.MapFrom(src => src.PortfolioType.Name));
//.ReverseMap();
}
}
----- EDITAR -----
Después de leer los documentos vinculados en los comentarios de Lucian Bargaoanu, creo que es mejor cambiar un poco esta respuesta.
El sin parámetros services.AddAutoMapper()
(que tenía la respuesta @saineshwar) ya no funciona (al menos para mí). Pero si usa el ensamblado NuGet AutoMapper.Extensions.Microsoft.DependencyInjection, el marco puede inspeccionar todas las clases que extienden AutoMapper.Profile (como el mío, MappingProfile).
Entonces, en mi caso, donde la clase pertenece al mismo ensamblaje en ejecución, el registro del servicio se puede acortar a services.AddAutoMapper(System.Reflection.Assembly.GetExecutingAssembly());
(Un enfoque más elegante podría ser una extensión sin parámetros con esta codificación).
Gracias Lucian!
Estoy usando AutoMapper 6.1.1 y asp.net Core 1.1.2.
En primer lugar, defina las clases de perfil heredadas por la clase de perfil de Automapper. Creé la interfaz IProfile que está vacía, el propósito es solo encontrar las clases de este tipo.
public class UserProfile : Profile, IProfile
{
public UserProfile()
{
CreateMap<User, UserModel>();
CreateMap<UserModel, User>();
}
}
Ahora cree una clase separada, por ejemplo, asignaciones
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
});
}
}
}
}
Ahora en MVC Core web Project en el archivo Startup.cs, en el constructor, llame a la clase Mapping que inicializará todas las asignaciones en el momento de la carga de la aplicación.
Mappings.RegisterMappings();
Para ASP.NET Core (probado con 2.0+ y 3.0), si prefiere leer la documentación de origen: https://github.com/AutoMapper/AutoMapper.Extensions.Microsoft.DependencyInjection/blob/master/README.md
De lo contrario, seguir estos 4 pasos funciona:
Instale AutoMapper.Extensions.Microsoft.DependancyInjection desde nuget.
Simplemente agregue algunas clases de perfil.
Luego agregue a continuación a su clase startup.cs.
services.AddAutoMapper(OneOfYourProfileClassNamesHere)
Luego, simplemente inyecte IMapper en sus controladores o donde lo necesite:
public class EmployeesController {
private readonly IMapper _mapper;
public EmployeesController(IMapper mapper){
_mapper = mapper;
}
Y si quieres usar ProjectTo es ahora simplemente:
var customers = await dbContext.Customers.ProjectTo<CustomerDto>(_mapper.ConfigurationProvider).ToListAsync()
Para AutoMapper 9.0.0:
public static IEnumerable<Type> GetAutoMapperProfilesFromAllAssemblies()
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var aType in assembly.GetTypes())
{
if (aType.IsClass && !aType.IsAbstract && aType.IsSubclassOf(typeof(Profile)))
yield return aType;
}
}
}
MapperProfile:
public class OrganizationProfile : Profile
{
public OrganizationProfile()
{
CreateMap<Foo, FooDto>();
// Use CreateMap... Etc.. here (Profile methods are the same as configuration methods)
}
}
En tu inicio:
services.AddAutoMapper(GetAutoMapperProfilesFromAllAssemblies()
.ToArray());
En Controlador o servicio: Inyectar mapeador:
private readonly IMapper _mapper;
Uso:
var obj = _mapper.Map<TDest>(sourceObject);
Para agregar a lo que Arve Systad mencionó para las pruebas. Si por alguna razón eres como yo y quieres mantener la estructura de herencia proporcionada en la solución deutz, puedes configurar MapperConfiguration de esta manera:
var mappingProfile = new MappingProfile();
var config = new MapperConfiguration(cfg =>
{
cfg.AddProfile(mappingProfile);
});
var mapper = new Mapper(config);
Hice esto en NUnit.
servicios.AddAutoMapper (); No funcionó para mí. (Estoy usando Asp.Net Core 2.0)
Después de configurar como a continuación
var config = new AutoMapper.MapperConfiguration(cfg =>
{
cfg.CreateMap<ClientCustomer, Models.Customer>();
});
inicializar el mapeador IMapper mapper = config.CreateMapper ();
y agregue el objeto del mapeador a los servicios como servicios singleton. AddSingleton (mapeador);
de esta manera puedo agregar una DI al controlador
private IMapper autoMapper = null;
public VerifyController(IMapper mapper)
{
autoMapper = mapper;
}
y he usado lo siguiente en mis métodos de acción
ClientCustomer customerObj = autoMapper.Map<ClientCustomer>(customer);
acerca de la respuesta thez, no hay necesidad de especificar el parámetro de mapeador IMapper en el constructor de controladores.
puede usar el asignador, ya que es un miembro estático en cualquier lugar del código.
public class UserController : Controller {
public someMethod()
{
Mapper.Map<User, UserDto>(user);
}
}
IMapper
puede burlarse de eso y, por ejemplo, simplemente hacer que devuelva nulo si es irrelevante para la prueba dada.