asp.net - setup - Automapper-Mapper ya inicializado error




setup automapper (6)

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; }
}

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);
    }
}

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();
}

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 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;
}