webentwicklung-frage-antwort-db.com.de

Automapper - Mapper hat den Fehler bereits initialisiert

Ich verwende AutoMapper 6.2.0 in meiner ASP.NET MVC 5-Anwendung.

Wenn ich meine Ansicht über den Controller anrufe, werden alle Dinge richtig angezeigt. Wenn ich diese Ansicht aktualisiere, zeigt Visual Studio einen Fehler: 

System.InvalidOperationException: 'Mapper wurde bereits initialisiert. Sie müssen Initialize einmal pro Anwendungsdomäne prozess aufrufen. '

Ich verwende AutoMapper nur in einem Controller. Noch an keiner Stelle eine Konfiguration vorgenommen und AutoMapper in keinem anderen Dienst oder Controller verwendet.

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

Fehler im Controller:

/ - enter image description here

Meine Modellklasse:

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

Meine ViewModel-Klasse:

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; }
}
22
Rahmat Ali

Wenn Sie die Ansicht aktualisieren, erstellen Sie eine neue Instanz von StudentsController - und initialisieren somit Ihren Mapper neu. Dies führt zur Fehlermeldung "Mapper bereits initialisiert".

Aus dem Erste Schritte

Wo konfiguriere ich AutoMapper?

Wenn Sie die statische Mapper-Methode verwenden, sollte die Konfiguration nur einmal pro AppDomain vorgenommen werden. Dies bedeutet, dass der Konfigurationscode am besten im Anwendungsstart abgelegt werden kann, beispielsweise in der Datei "Global.asax" für ASP.NET-Anwendungen.

Sie können dies einrichten, indem Sie alle Ihre Mapping-Konfigurationen in einer statischen Methode speichern.

App_Start/AutoMapperConfig.cs:

public class AutoMapperConfig
{
    public static void Initialize()
    {
        Mapper.Initialize(cfg =>
        {
            cfg.CreateMap<Student, StudentViewModel>();
            ...
        });
    }
}

Dann rufen Sie diese Methode in Global.asax.cs auf.

protected void Application_Start()
{
    App_Start.AutoMapperConfig.Initialize();
}

Jetzt können Sie es in Ihren Controller-Aktionen (wieder) verwenden.

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

Wenn Sie in einem Komponententestszenario bei der statischen Implementierung bleiben möchten/müssen, beachten Sie, dass Sie AutoMapper.Mapper.Reset() aufrufen können, bevor Sie initialize aufrufen. Beachten Sie, dass dies nicht im Produktionscode verwendet werden sollte, wie in der Dokumentation angegeben. 

Quelle: http://docs.automapper.org/de/stable/Configuration.html#resetting-static-mapping-configuration

27
dasch88

Ich habe diese Methode schon einmal verwendet und bis Version 6.1.1 funktioniert

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

Seit Version 6.2 funktioniert das nicht mehr. Um Automapper korrekt zu verwenden, erstellen Sie einen neuen Mapper und verwenden Sie diesen wie folgt:

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

Falls Sie AutoMapper wirklich "neu initialisieren" müssen, sollten Sie zur instanzbasierten API wechseln , um System.InvalidOperationException zu vermeiden: Mapper already initialized. You must call Initialize once per application domain/process.

Wenn Sie beispielsweise die Variable TestServer für xUnit erstellen, können Sie ServiceCollectionExtensions.UseStaticRegistration innerhalb des Klassenkonstruktors fixure einfach auf false setzen, um den Trick auszuführen:

public TestServerFixture()
{
    ServiceCollectionExtensions.UseStaticRegistration = false; // <-- HERE

    var hostBuilder = new WebHostBuilder()
        .UseEnvironment("Testing")
        .UseStartup<Startup>();

    Server = new TestServer(hostBuilder);
    Client = Server.CreateClient();
}
16
Dmitry Pavlov

Sie können automapper verwenden, da Static API und Instance API, Mapper, der bereits initialisiert ist , ein häufiges Problem in ist Statische API, Sie können mapper.Reset () verwenden, wo Sie mapper initialisiert haben, aber dies ist überhaupt keine Antwort.

Versuchen Sie es einfach mit der Instanz-API

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);
5
Thisara Subath

Für Unit-Tests können Sie Mapper.Reset () zu Ihrer Unit-Test-Klasse hinzufügen

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

Automapper 8.0.0 Version

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

Sie können einfach Mapper.Reset() verwenden.

Beispiel: 

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

Wenn Sie Mapper in UnitTest verwenden und Ihre Tests mehr als eine durchführen, können Sie Mapper.Reset()

//Your mapping.
 public static void Initialize()
 {
   Mapper.Reset();                    
   Mapper.Initialize(cfg =>
   {  
       cfg.CreateMap<***>    
   }

//Your test classes.

 [TestInitialize()]
 public void Initialize()
 {
      AutoMapping.Initialize();
 }
0
adaniak
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());
                    }
                    );
            }
        }
0
Nikola Nikolov

Wenn Sie MsTest verwenden, können Sie das AssemblyInitialize-Attribut verwenden, damit die Zuordnung für diese Assembly nur einmal konfiguriert wird (hier test Assembly). Dies wird im Allgemeinen zur Basisklasse von Controller-Unit-Tests hinzugefügt.

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

Ich hoffe diese Antwort hilft

0