Automapper - Mapper already initialized error

2020-02-11 17:59发布

I am using AutoMapper 6.2.0 in my ASP.NET MVC 5 application.

When I call my view through controller it shows all things right. But, when I refresh that view, Visual Studio shows an error:

System.InvalidOperationException: 'Mapper already initialized. You must call Initialize once per application domain/process.'

I am using AutoMapper only in one controller. Not made any configuration in any place yet nor used AutoMapper in any other service or controller.

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

Error within controller:

enter image description here

My Model class:

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

My ViewModel Class:

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

11条回答
男人必须洒脱
2楼-- · 2020-02-11 18:35

If you want/need to stick with the static implementation in a unit testing scenario, note that you can call AutoMapper.Mapper.Reset() before calling initialize. Do note that this should not be used in production code as noted in the documentation.

Source: AutoMapper documentation.

查看更多
虎瘦雄心在
3楼-- · 2020-02-11 18:35

If you are using MsTest you can use the AssemblyInitialize attribute so that mapping gets configured only once for that assembly (here test assembly). This is generally added into to the base class of controller unit tests.

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

I hope this answer helps

查看更多
萌系小妹纸
4楼-- · 2020-02-11 18:38

Automapper 8.0.0 version

    AutoMapper.Mapper.Reset();
    Mapper.Initialize(
     cfg => {
         cfg.CreateMap<sourceModel,targetModel>();
       }
    );
查看更多
【Aperson】
5楼-- · 2020-02-11 18:40

You can use automapper as Static API and Instance API , Mapper already initialized is common issue in Static API , you can use mapper.Reset() where you initialized mapper but this this not an answer at all.

Just try with instance 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);
查看更多
Root(大扎)
6楼-- · 2020-02-11 18:41

For Unit Testing, you can add Mapper.Reset() to your unit test class

[TearDown]
public void TearDown()
{
    Mapper.Reset();
}
查看更多
虎瘦雄心在
7楼-- · 2020-02-11 18:43

I've used this method before and it worked till version 6.1.1

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

Since version 6.2, this doesn't work any more. To correctly use Automapper create a new Mapper and us this one like this:

 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);
查看更多
登录 后发表回答