asp.net - initialize - profile automapper
Automapper-Mapper ya inicializado error (9)
Cuando actualiza la vista, está creando una nueva instancia de StudentsController
y, por lo tanto, reinicializando su asignador, lo que da como resultado el mensaje de error "El asignador ya está inicializado".
De la guía de introducción
¿Dónde configuro AutoMapper?
Si está utilizando el método del asignador estático, la configuración solo debería ocurrir una vez por cada dominio de aplicación. Eso significa que el mejor lugar para colocar el código de configuración es en el inicio de la aplicación, como el archivo Global.asax para aplicaciones ASP.NET.
Una forma de configurar esto es colocar todas sus configuraciones de mapeo en un método estático.
App_Start / AutoMapperConfig.cs :
public class AutoMapperConfig
{
public static void Initialize()
{
Mapper.Initialize(cfg =>
{
cfg.CreateMap<Student, StudentViewModel>();
...
});
}
}
Entonces llama a este método en el Global.asax.cs
protected void Application_Start()
{
App_Start.AutoMapperConfig.Initialize();
}
Ahora puede (re) usarlo en las acciones de su controlador.
public class StudentsController : Controller
{
public ActionResult Index(int id)
{
var query = db.Students.Where(...);
var students = AutoMapper.Mapper.Map<List<StudentViewModel>>(query.ToList());
return View(students);
}
}
Estoy usando AutoMapper 6.2.0 en mi aplicación ASP.NET MVC 5.
Cuando llamo a mi vista a través del controlador, todo se ve bien. Pero, cuando actualizo esa vista, Visual Studio muestra un error:
System.InvalidOperationException: ''Mapper ya inicializado. Debe llamar Inicializar una vez por dominio / proceso de aplicación ''.
Estoy usando AutoMapper solo en un controlador. Aún no se ha realizado ninguna configuración en ningún lugar ni se ha utilizado AutoMapper en ningún otro servicio o controlador.
Mi controlador
public class StudentsController : Controller
{
private DataContext db = new DataContext();
// GET: Students
public ActionResult Index([Form] QueryOptions queryOptions)
{
var students = db.Students.Include(s => s.Father);
AutoMapper.Mapper.Initialize(cfg =>
{
cfg.CreateMap<Student, StudentViewModel>();
});
return View(new ResulList<StudentViewModel> {
QueryOptions = queryOptions,
Model = AutoMapper.Mapper.Map<List<Student>,List<StudentViewModel>>(students.ToList())
});
}
// Other Methods are deleted for ease...
Error dentro del controlador:
Mi clase de modelo:
public class Student
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string CNIC { get; set; }
public string FormNo { get; set; }
public string PreviousEducaton { get; set; }
public string DOB { get; set; }
public int AdmissionYear { get; set; }
public virtual Father Father { get; set; }
public virtual Sarparast Sarparast { get; set; }
public virtual Zamin Zamin { get; set; }
public virtual ICollection<MulaqatiMehram> MulaqatiMehram { get; set; }
public virtual ICollection<Result> Results { get; set; }
}
Mi clase de ViewModel:
public class StudentViewModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string CNIC { get; set; }
public string FormNo { get; set; }
public string PreviousEducaton { get; set; }
public string DOB { get; set; }
public int AdmissionYear { get; set; }
public virtual FatherViewModel Father { get; set; }
public virtual SarparastViewModel Sarparast { get; set; }
public virtual ZaminViewModel Zamin { get; set; }
}
En caso de que realmente necesite "reinicializar" AutoMapper
, debe cambiar a la API basada en la instancia para evitar la System.InvalidOperationException
: el Mapper already initialized. You must call Initialize once per application domain/process.
Mapper already initialized. You must call Initialize once per application domain/process.
Por ejemplo, cuando está creando las pruebas TestServer
para xUnit
, simplemente puede establecer ServiceCollectionExtensions.UseStaticRegistration
dentro del constructor de la clase de fixure
en false
para hacer el truco:
public TestServerFixture()
{
ServiceCollectionExtensions.UseStaticRegistration = false; // <-- HERE
var hostBuilder = new WebHostBuilder()
.UseEnvironment("Testing")
.UseStartup<Startup>();
Server = new TestServer(hostBuilder);
Client = Server.CreateClient();
}
He usado este método antes y funcionó hasta la versión 6.1.1
Mapper.Initialize(cfg => cfg.CreateMap<ContactModel, ContactModel>()
.ConstructUsing(x => new ContactModel(LoggingDelegate))
.ForMember(x => x.EntityReference, opt => opt.Ignore())
);
Desde la versión 6.2, esto ya no funciona. Para usar correctamente Automapper, cree un nuevo Mapeador y este como este:
var mapper = new MapperConfiguration(cfg => cfg.CreateMap<ContactModel, ContactModel>()
.ConstructUsing(x => new ContactModel(LoggingDelegate))
.ForMember(x => x.EntityReference, opt => opt.Ignore())).CreateMapper();
var model = mapper.Map<ContactModel>(this);
Para la prueba de unidad, puede agregar Mapper.Reset () a su clase de prueba de unidad
[TearDown]
public void TearDown()
{
Mapper.Reset();
}
Puede usar automapper como API estática e API de instancia , el asignador ya inicializado es un problema común en la API estática, puede usar mapper.Reset () donde inicializó el asignador, pero esto no es una respuesta.
Solo intente con la API de instancia
var students = db.Students.Include(s => s.Father);
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<Student, StudentViewModel>();
});
IMapper iMapper = config.CreateMapper();
return iMapper.Map<List<Student>, List<StudentViewModel>>(students);
Si desea o necesita seguir con la implementación estática en un escenario de prueba de unidad, tenga en cuenta que puede llamar a AutoMapper.Mapper.Reset()
antes de iniciar la llamada. Tenga en cuenta que esto no debe utilizarse en el código de producción como se indica en la documentación.
Fuente: http://docs.automapper.org/en/stable/Configuration.html#resetting-static-mapping-configuration
Si está usando Mapper en UnitTest y sus pruebas más de una, puede usar Mapper.Reset()
//Your mapping.
public static void Initialize()
{
Mapper.Reset();
Mapper.Initialize(cfg =>
{
cfg.CreateMap<***>
}
//Your test classes.
[TestInitialize()]
public void Initialize()
{
AutoMapping.Initialize();
}
Simplemente puede utilizar Mapper.Reset()
.
Ejemplo:
public static TDestination MapToObject<TSource, TDestination>(TSource Obj)
{
Mapper.Initialize(cfg => cfg.CreateMap<TSource, TDestination>());
TDestination tDestination = Mapper.Map<TDestination>(Obj);
Mapper.Reset();
return tDestination;
}
Automapper versión 8.0.0
AutoMapper.Mapper.Reset();
Mapper.Initialize(
cfg => {
cfg.CreateMap<sourceModel,targetModel>();
}
);