31

我在我的 ASP.NET MVC 5 应用程序中使用 AutoMapper 6.2.0。

当我通过控制器调用我的视图时,它会显示所有内容。但是,当我刷新该视图时,Visual Studio 显示错误:

System.InvalidOperationException: '映射器已经初始化。您必须为每个应用程序域/进程调用一次初始化。

我只在一个控制器中使用 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; }
}

我的视图模型类:

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

11 回答 11

44

如果您想/需要在单元测试场景中坚持使用静态实现,请注意您可以AutoMapper.Mapper.Reset()在调用初始化之前调用。请注意,如文档中所述,这不应在生产代码中使用。

资料来源:AutoMapper 文档

于 2017-12-05T17:00:27.577 回答
24

当您刷新视图时,您正在创建一个新的实例StudentsController- 并因此重新初始化您的 Mapper - 导致错误消息“Mapper 已初始化”。

入门指南

我在哪里配置 AutoMapper?

如果您使用的是静态 Mapper 方法,则每个 AppDomain 只应进行一次配置。这意味着放置配置代码的最佳位置是在应用程序启动中,例如用于 ASP.NET 应用程序的 Global.asax 文件。

设置它的一种方法是将所有映射配置放入静态方法中。

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);
    }
}
于 2017-11-11T20:26:34.093 回答
20

我以前用过这个方法,它一直工作到 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);
于 2017-11-13T13:41:05.273 回答
17

如果您真的需要“重新初始化” AutoMapper,您应该切换到基于实例的 API以避免System.InvalidOperationExceptionMapper already initialized. You must call Initialize once per application domain/process.

例如,当您创建TestServerforxUnit测试时,您只需ServiceCollectionExtensions.UseStaticRegistrationfixure类构造函数中设置false即可:

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

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

    Server = new TestServer(hostBuilder);
    Client = Server.CreateClient();
}
于 2017-11-29T12:04:51.160 回答
7

您可以将 automapper 用作Static APIInstance APIMapper 已经初始化是 Static API 中的常见问题,您可以在初始化 mapper 的地方使用mapper.Reset() 但这根本不是答案。

只需尝试使用实例 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);
于 2018-08-10T06:59:22.440 回答
7

对于单元测试,您可以将 Mapper.Reset() 添加到您的单元测试类

[TearDown]
public void TearDown()
{
    Mapper.Reset();
}
于 2018-08-16T12:29:49.187 回答
6

Automapper 8.0.0 版本

    AutoMapper.Mapper.Reset();
    Mapper.Initialize(
     cfg => {
         cfg.CreateMap<sourceModel,targetModel>();
       }
    );
于 2018-12-05T13:10:12.337 回答
1

您可以简单地使用Mapper.Reset().

例子:

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;
}
于 2018-09-03T09:56:06.210 回答
0

如果您在 UnitTest 中使用 Mapper 并且您的测试不止一个,您可以使用Mapper.Reset()

`

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

//Your test classes.

 [TestInitialize()]
 public void Initialize()
 {
      AutoMapping.Initialize();
 }`
于 2018-11-16T09:21:31.420 回答
0

如果您使用的是 MsTest,则可以使用 AssemblyInitialize 属性,以便为该程序集(此处为测试程序集)配置一次映射。这通常被添加到控制器单元测试的基类中。

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

我希望这个答案有帮助

于 2019-02-25T17:17:27.773 回答
0
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());
                    }
                    );
            }
        }
于 2019-05-20T18:54:43.990 回答