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:
/ -
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; }
}
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);
}
}
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
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);
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();
}
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);
Für Unit-Tests können Sie Mapper.Reset () zu Ihrer Unit-Test-Klasse hinzufügen
[TearDown]
public void TearDown()
{
Mapper.Reset();
}
Automapper 8.0.0 Version
AutoMapper.Mapper.Reset();
Mapper.Initialize(
cfg => {
cfg.CreateMap<sourceModel,targetModel>();
}
);
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;
}
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();
}
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());
}
);
}
}
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