asp.net - примеры - Automapper-Mapper уже инициализировал ошибку




automapper.net core (6)

Я использую AutoMapper 6.2.0 в моем приложении ASP.NET MVC 5.

Когда я называю свой взгляд через контроллер, он показывает все правильно. Но когда я обновляю это представление, Visual Studio показывает ошибку:

System.InvalidOperationException: 'Mapper уже инициализирован. Вы должны вызвать Initialize один раз для домена / процесса приложения. '

Я использую AutoMapper только в одном контроллере. Пока что не было выполнено ни одной настройки ни в одном месте, ни AutoMapper ни в каком другом сервисе или контроллере.

Мой контроллер:

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

Ошибка в контроллере:

Моя модель класса:

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

Мой класс 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; }
}

В случае, если вам действительно нужно «повторно инициализировать» AutoMapper вам следует переключиться на API, основанный на экземплярах, чтобы избежать System.InvalidOperationException : Mapper already initialized. You must call Initialize once per application domain/process. Mapper already initialized. You must call Initialize once per application domain/process.

Например, когда вы создаете TestServer для тестов xUnit вы можете просто установить ServiceCollectionExtensions.UseStaticRegistration в fixure класса fixure в значение false чтобы сделать хитрость:

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

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

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

Вы можете использовать automapper в качестве статического API и API- интерфейса экземпляра. Уже инициализированный Mapper является распространенной проблемой статического API, вы можете использовать mapper.Reset (), где вы инициализировали mapper, но это вовсе не ответ.

Просто попробуйте с экземпляром 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);

Для модульного тестирования вы можете добавить Mapper.Reset () в свой класс модульного тестирования.

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

Если вы используете Mapper в UnitTest и ваши тесты более одного, вы можете использовать Mapper.Reset()

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

//Your test classes.

 [TestInitialize()]
 public void Initialize()
 {
      AutoMapping.Initialize();
 }

Когда вы обновляете представление, вы создаете новый экземпляр StudentsController - и, следовательно, повторно инициализируете свой Mapper - в результате появляется сообщение об ошибке «Mapper уже инициализирован».

Из руководства по началу работы

Где я могу настроить AutoMapper?

Если вы используете статический метод Mapper, настройка должна происходить только один раз для каждого AppDomain. Это означает, что лучшее место для размещения кода конфигурации - это запуск приложения, например, файл Global.asax для приложений ASP.NET.

Один из способов установить это - поместить все ваши конфигурации сопоставления в статический метод.

App_Start / AutoMapperConfig.cs :

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

Затем вызовите этот метод в Global.asax.cs

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

Теперь вы можете (повторно) использовать его в действиях вашего контроллера.

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

Я использовал этот метод раньше, и он работал до версии 6.1.1

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

Начиная с версии 6.2, это больше не работает. Чтобы правильно использовать Automapper, создайте новый Mapper и нам этот вот так:

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