c# - Configuración de AutoMapper 4.2 con IoC integrado en ASP.NET Core 1.0 MVC6
asp.net-core-1.0 (5)
Estoy tratando de encontrar la manera correcta de configurar AutoMapper en el archivo Startup.cs de mi aplicación y luego usarlo en toda mi aplicación.
Estoy tratando de usar esta documentación que explica de alguna manera cómo dar a AutoMapper una sensación estática sin la antigua API estática. El ejemplo utiliza StructureMap.
Me gustaría saber cómo puedo hacer algo similar, pero en una aplicación Core 1.0 utilizando el contenedor de servicios integrado.
Estoy asumiendo que en la función Configurar configuraría AutoMapper y luego en la función Configurar Servicios lo agregaría como un transitorio.
Supongo que, al final, la forma más limpia y adecuada de hacerlo es mediante la inyección de dependencia. Aquí está mi intento actual pero no está funcionando:
Startup.cs
public IMapper Mapper { get; set; }
private MapperConfiguration MapperConfiguration { get; set; }
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IMapper, Mapper>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
MapperConfiguration MapperConfiguration = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Product, ProductViewModel>().ReverseMap();
});
Mapper = MapperConfiguration.CreateMapper();
}
En mi controlador:
private IMapper _mapper { get; set; }
// Constructor
public ProductsController(IMapper mapper)
{
_mapper = mapper;
}
public IActionResult Create(ProductViewModel vm)
{
Product product = _mapper.Map<ProductViewModel, Product>(vm);
}
Simplemente no funciona en absoluto ... debo faltar algún paso o hacer algo mal.
En sus servicios de configuración, puede crear una instancia de MapperConfiguration y luego crear sus mapas y agregarlos.
public void ConfigureServices(IServiceCollection services)
{
MapperConfiguration configuration = new MapperConfiguration(cfg =>
{
cfg.AddProfile<MappingProfile.Profile1>();
cfg.AddProfile<MappingProfile.Profile2>();
});
services.AddInstance(typeof (IMapper), configuration.CreateMapper());
}
Luego simplemente inyectas el IMapper en tu constructor y mapa.
public class Handler
{
private readonly ProfileContext _db;
private readonly IMapper _mapper;
public Handler(ProfileContext db, IMapper mapper)
{
_db = db;
_mapper = mapper;
}
public void Handle(Profile1 request)
{
ProfileModel profile = _mapper.Map<Profile1, ProfileModel>(request);
_db.Profiles.Add(profile);
try
{
db.SaveChanges();
}
catch (Exception ex)
{
throw;
}
return profile;
}
}
Esta respuesta se adapta al enfoque de MVC 6 un poco más alrededor de la capa del Controlador:
Migré de AutoMapper 4.1.1 a 4.2.0, tuve algunos problemas para descubrir las complejidades pero llegué al final.
Primero, separé la compilación de AutoMapper Profile en una nueva clase (ver más abajo) para evitar la obstrucción de la clase de inicio.
using AutoMapper;
using YourModels;
using YourViewModels;
namespace YourNamespace
{
public class AutoMapperProfileConfiguration : Profile
{
protected override void Configure()
{
CreateMap<Application, ApplicationViewModel>();
CreateMap<ApplicationViewModel, Application>();
...
}
}
}
Hice las siguientes enmiendas a la clase de inicio.
Agregué una variable miembro privada de tipo MapperConfiguration.
private MapperConfiguration _mapperConfiguration { get; set; }
En el constructor de inicio, agregué el siguiente código para crear una instancia de mi nuevo perfil de AutoMapper.
_mapperConfiguration = new MapperConfiguration(cfg =>
{
cfg.AddProfile(new AutoMapperProfileConfiguration());
});
En ConfigureServices()
dejé mi nuevo perfil de AutoMapper en un Singleton.
services.AddSingleton<IMapper>(sp => _mapperConfiguration.CreateMapper());
Entonces fue solo una simple operación inyectar los controladores relevantes.
using AutoMapper;
using ...
namespace YourNamespace
{
public class ApplicationsController : BaseController
{
[FromServices]
private IMapper _mapper { get; set; }
[FromServices]
private IApplicationRepository _applicationRepository { get; set; }
public ApplicationsController(
IMapper mapper,
IApplicationRepository applicationRepository)
{
_mapper = mapper;
_applicationRepository = applicationRepository;
}
// GET: Applications
public async Task<IActionResult> Index()
{
IEnumerable<Application> applications = await _applicationRepository.GetForIdAsync(...);
if (applications == null)
return HttpNotFound();
List<ApplicationViewModel> viewModel = _mapper.Map<List<ApplicationViewModel>>(applications);
return View(viewModel);
}
...
}
Gracias a Rexebin en https://pintoservice.wordpress.com/2016/01/31/dependency-injection-for-automapper-4-2-in-asp-net-vnext-mvc-project/ por su publicación que ayuda enormemente
La respuesta publicada es una gran solución, pero pensé que les haría saber cómo lo estoy haciendo actualmente con Core 1.0 y AutoMapper v5.1.1. Siento que es un enfoque muy agradable y fácil de entender.
En Startup.cs en la parte superior del método Configurar, simplemente escriba el siguiente código para inicializar sus asignaciones:
Mapper.Initialize(config =>
{
config.CreateMap<ProductViewModel, Product>().ReverseMap();
config.CreateMap<CustomerViewModel, Customer>().ReverseMap();
});
Luego, en su controlador o en cualquier otra parte de su código donde necesite mapear:
Mapper.Map<Product>(productViewModel);
Solo estoy experimentando con mover una API web de .net 4.5 a .net core y necesitaba esto. Estuviste muy cerca, ya que @DavidGouge sugirió que necesitas registrar la instancia del mapeador que has creado en el IOC. Por lo tanto, la configuración de AutoMapper debe realizarse en ConfigureServices. (Se ha incluido en la línea aquí, pero en mi proyecto llama a un método en una clase AutoMapperConfiguration, por lo que el inicio se mantiene lo más limpio posible, lo mismo que con los registros IOC). El IMapper se llenará correctamente en su controlador.
Startup.cs se convierte en
public IMapper Mapper { get; set; }
private MapperConfiguration MapperConfiguration { get; set; }
public void ConfigureServices(IServiceCollection services)
{
MapperConfiguration MapperConfiguration = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Product, ProductViewModel>().ReverseMap();
});
Mapper = MapperConfiguration.CreateMapper();
services.AddInstance(Mapper);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// AutoMapper Configuration moved out of here.
}
También puede utilizar el paquete de extensión desde el creador de automapper.
Puede pasar una configuración, especificar ensamblajes para escanear o no pasar nada y dejar que escanee ensamblajes desde DependencyContext.
https://github.com/AutoMapper/AutoMapper.Extensions.Microsoft.DependencyInjection
https://www.nuget.org/packages/AutoMapper.Extensions.Microsoft.DependencyInjection/
public void ConfigureServices(IServiceCollection services)
{
//configure DI
services.AddTransient<IFoo, Foo>();
//Add automapper - scans for Profiles
services.AddAutoMapper();
//or specify
services.AddAutoMapper(cfg =>
{
cfg.AddProfile<ViewModelProfile>();
...
});
...