asp.net - net - Automapper: errore di inizializzazione già mappato




service add automapper (8)

È possibile utilizzare automapper come API statica e API di istanza , il mapping già inizializzato è un problema comune in API statiche, è possibile utilizzare mapper.Reset () in cui è stato inizializzato il programma di mappatura ma questa non è affatto una risposta.

Prova con l'API di istanza

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

Sto usando AutoMapper 6.2.0 nella mia applicazione ASP.NET MVC 5.

Quando chiamo la mia vista attraverso il controller, mostra tutto bene. Ma quando aggiorno quella vista, Visual Studio mostra un errore:

System.InvalidOperationException: 'Mapper già inizializzato. È necessario chiamare Initialize una volta per dominio / processo dell'applicazione. '

Sto usando AutoMapper solo su un controller. Non è stata effettuata alcuna configurazione in alcun luogo, né utilizzato AutoMapper in nessun altro servizio o controller.

Il mio controller:

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...

Errore nel controller:

La mia classe di modello:

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

La mia classe 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; }
}

Ho usato questo metodo prima e ha funzionato fino alla versione 6.1.1

 Mapper.Initialize(cfg => cfg.CreateMap<ContactModel, ContactModel>()
            .ConstructUsing(x => new ContactModel(LoggingDelegate))
            .ForMember(x => x.EntityReference, opt => opt.Ignore())
        );

Dalla versione 6.2, questo non funziona più. Per usare correttamente Automapper crea un nuovo Mapper e noi questo in questo modo:

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

Per il test unitario, è possibile aggiungere Mapper.Reset () alla classe di test dell'unità

[TearDown]
public void TearDown()
{
    Mapper.Reset();
}

Puoi semplicemente usare Mapper.Reset() .

Esempio:

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


Se si utilizza MsTest, è possibile utilizzare l'attributo AssemblyInitialize in modo che la mappatura venga configurata una sola volta per quell'assembly (qui assembly di test). Questo è generalmente aggiunto alla classe base dei test dell'unità di controllo.

[TestClass]
public class BaseUnitTest
{
    [AssemblyInitialize]
    public static void AssemblyInit(TestContext context)
    {
        AutoMapper.Mapper.Initialize(cfg =>
        {
            cfg.CreateMap<Source, Destination>()
                .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.EmailAddress));
        });
    }
}

Spero che questa risposta aiuti


Versione di Automapper 8.0.0

    AutoMapper.Mapper.Reset();
    Mapper.Initialize(
     cfg => {
         cfg.CreateMap<sourceModel,targetModel>();
       }
    );

private static bool _mapperIsInitialized = false;
        public InventoryController()
        {

            if (!_mapperIsInitialized)
            {

                _mapperIsInitialized = true;
                Mapper.Initialize(
                    cfg =>
                    {
                        cfg.CreateMap<Inventory, Inventory>()
                        .ForMember(x => x.Orders, opt => opt.Ignore());
                    }
                    );
            }
        }