Automapper - Mapper已初始化错误

时间:2017-11-11 19:01:10

标签: asp.net asp.net-mvc automapper automapper-6

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

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

  

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

我只在一个控制器中使用AutoMapper。尚未在任何地方进行任何配置,也未在任何其他服务或控制器中使用AutoMapper。

我的控制器:

admin.auth().verifyIdToken(idToken)...

控制器内的错误:

in this example

我的模特课:

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

我的ViewModel类:

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

11 个答案:

答案 0 :(得分:31)

如果您希望/需要在单元测试场景中坚持使用静态实现,请注意您可以在调用initialize之前调用AutoMapper.Mapper.Reset()。请注意,这不应该在文档中提到的生产代码中使用。

来源:http://docs.automapper.org/en/stable/Configuration.html#resetting-static-mapping-configuration

答案 1 :(得分:22)

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

来自Getting Started Guide

  

我在哪里配置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);
    }
}

答案 2 :(得分:18)

之前我使用过此方法,直到版本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);

答案 3 :(得分:16)

如果你真的需要&#34;重新初始化&#34; System.InvalidOperationException您应该switch to the instance based API避免Mapper already initialized. You must call Initialize once per application domain/process.TestServer

例如,在为xUnit测试创建ServiceCollectionExtensions.UseStaticRegistration时,您只需将fixure类构造函数中的false设置为public TestServerFixture() { ServiceCollectionExtensions.UseStaticRegistration = false; // <-- HERE var hostBuilder = new WebHostBuilder() .UseEnvironment("Testing") .UseStartup<Startup>(); Server = new TestServer(hostBuilder); Client = Server.CreateClient(); } 即可:

         from     to    color
    1   54770  54771 darkgrey
    2   54770  54775 darkgrey
    3   54770  54776 darkgrey
    4   54770  54774 darkgrey
    5   54771  54775 darkgrey
    6   54771  54776 darkgrey
    7   54771  54774      red
    8   54775  54776 darkgrey
    9   54775  54774 darkgrey
    10  54776  54774 darkgrey
    11 110780 110781 darkgrey
    12 110780 110783 darkgrey
    13 110780 110784 darkgrey
    14 110780 110782 darkgrey
    15 110781 110783 darkgrey
    16 110781 110784 darkgrey
    17 110781 110782 darkgrey
    18 110783 110784 darkgrey
    19 110783 110782 darkgrey
    20 110784 110782 darkgrey
    21  20285  20286 darkgrey
    22  20285  20287 darkgrey
    23  20285  20692      red
    24  20285  20693      red
    25  20286  20287 darkgrey
    26  20286  20692 darkgrey
    27  20286  20693 darkgrey
    28  20287  20692 darkgrey
    29  20287  20693 darkgrey
    30  83962  83963 darkgrey
    31  83962  83964 darkgrey
    32  83962  83960 darkgrey
    33  83962  83961      red
    34  83963  83964 darkgrey
    35  83963  83960 darkgrey
    36  83963  83961 darkgrey
    37  83964  83960      red
    38  83964  83961 darkgrey
    39  88564  88565 darkgrey
    40  88824  88825 darkgrey
    41  88824  88826 darkgrey
    42  88824  88565 darkgrey
    43  88825  88826 darkgrey
    44  88825  88565      red
    45  88826  88565 darkgrey
    46  72276  72272      red
    47  72276  72273 darkgrey
    48  72276  72274 darkgrey
    49  72276  72275 darkgrey
    50 111062 111058 darkgrey
    51 111062 111059 darkgrey
    52 111062 111060      red
    53 111062 111061 darkgrey
    54 111074 111070      red
    55 111074 111071      red
    56 111074 111072 darkgrey
    57 111074 111073 darkgrey

答案 4 :(得分:6)

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

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

答案 5 :(得分:5)

您可以将自动映射器用作静态API 实例API 已经初始化了映射器是静态API中的常见问题,您可以使用 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);

答案 6 :(得分:5)

Automapper 8.0.0版本

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

答案 7 :(得分: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;
}

答案 8 :(得分: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();
 }

答案 9 :(得分: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));
        });
    }
}

我希望这个答案有帮助

答案 10 :(得分: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());
                    }
                    );
            }
        }