自动映射器,映射器未初始化。使用正确的配置调用初始化。

13

当我尝试将数据提交到数据库时,我收到以下错误:

{"Success":false,"Error":true,"ErrorType":2,"Message":"System.InvalidOperationException: Mapper not initialized. Call Initialize with appropriate configuration. If you are trying to use mapper instances through a container or otherwise, make sure you do not have any calls to the static Mapper.Map methods, and if you're using ProjectTo or UseAsDataSource extension methods, make sure you pass in the appropriate IConfigurationProvider instance.\r\n at AutoMapper.Mapper.get_Instance()\r\n at AutoMapper.Mapper.Map(Object source, Object destination, Type sourceType, Type destinationType)\r\n at GoalPear.Web.Areas.PM.Controllers.CompanyController.SaveData(CompanyFormViewModel companyFormViewModel)

请告诉我为什么会出现这个错误,因为我经过了很多努力都无法弄清楚。

这是我的控制器代码:

public CompanyController() { }
private readonly ICompanyService _companyService;
public CompanyController(ICompanyService companyService) {
    _companyService = companyService;
}

这是控制器中的SaveData方法

[HttpPost]
public JsonResult SaveData(CompanyFormViewModel companyFormViewModel)
{
    try
    {
        int? id = null;
        Company company;
        if (companyFormViewModel.Id == null)
        {
            company = new Company();
        }
        else
        {
            id = (int)companyFormViewModel.Id;
            company = _companyService.GetCompany((int)id);
        }

        company = (Company)Mapper.Map(
            companyFormViewModel, 
            company, 
            typeof(CompanyFormViewModel), 
            typeof(Company));
        CompanyValidator companyValidator = new CompanyValidator();
        ValidationResult validationResult = companyValidator.Validate(company);

        if (validationResult.IsValid) //check for any validation errors
        {
            if (id == null)
            {
                _companyService.CreateCompany(company);
            }
            else
            {
                _companyService.Update(company);
            }

            _companyService.SaveCompany();
            return new JsonSuccessResult();
        }
        else
        {
            Response.StatusCode = (int)ResponseCode.UnprocessableEntity;
            return new JsonErrorResult(validationResult);
        }
    }
    catch (Exception ex)
    {
        Response.StatusCode = (int)ResponseCode.UnprocessableEntity;
        return new JsonErrorResult(ex.ToString());
    }
}

我的表单视图代码

@using (Html.BeginForm("SaveData", "Company", FormMethod.Post, new { @class = "", @id = "validate", @role = "form" })) { 
@*<form id="validate" method="POST" action="javascript:alert('Form #validate submited');">*@
<div class="head tac">
    <h1>Register Your Company With Us!!!</h1>
</div>
<div class="block">
    <div class="header">
        <div class="side pull-right">
            <button class="btn btn-default btn-clean" onclick="clear_form('#validate');" type="button">Clear form</button>
    </div>
</div>

<div class="content controls">
    <div class="form-row">
        <div class="col-md-3">Company Name:</div>
            <div class="col-md-9">
                @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "validate[required,maxSize[100]]", @placeholder = @Html.DisplayNameFor(model => model.Name) } })

            </div>
        </div>
        <div class="form-row">
            <div class="col-md-3">Owner Name:</div>
                <div class="col-md-9">
                    @Html.EditorFor(model => model.Owner, new { htmlAttributes = new { @class = "validate[required,maxSize[60]]", @placeholder = @Html.DisplayNameFor(model => model.Owner) } })

                </div>
            </div>
            <div class="form-row">
                <div class="col-md-3">Email:</div>
                    <div class="col-md-4">
                        @Html.EditorFor(model => model.Email, new { htmlAttributes = new { @class = "validate[required,maxSize[60]]" ,@type="email", @placeholder = @Html.DisplayNameFor(model => model.Email) } })
                    </div>
                </div>
                <div class="form-row">
                    <div class="col-md-3">Password:</div>
                    <div class="col-md-9">
                        @Html.EditorFor(model => model.Password, new { htmlAttributes = new { @class = "validate[required,maxSize[100]]", @type="password", @id="password", @placeholder = @Html.DisplayNameFor(model => model.Password) } })


                    </div>
                </div>
                <div class="form-row">
                    <div class="col-md-3">Confirm Password:</div>
                    <div class="col-md-9">
                        @Html.EditorFor(model => model.Password, new { htmlAttributes = new { @class = "validate[required,equals[password]]", @type = "password", @placeholder = @Html.DisplayNameFor(model => model.Password) } })

                    </div>
                </div>
        @* I have omitted some code from here for saving your time to read*@  

                <div class="form-row">
                    <div class="col-md-3">Address:</div>
                    <div class="col-md-9">

                        @Html.EditorFor(model => model.Address, new { htmlAttributes = new { @class = "validate[required,maxSize[60]]", @placeholder = @Html.DisplayNameFor(model => model.Address) } })
                    </div>
                </div>
            </div>
            <div class="footer">
                <div class="side pull-right">
                    <div class="btn-group">
                        <button class="btn btn-default" type="button" onclick="$('#validate').validationEngine('hide');">Hide prompts</button>
                        <button class="btn btn-success" type="submit">Submit</button>
                    </div>
                </div>
            </div>
        </div>
   }

这是我的公司模型代码

public string Name {get;set;}
public string Logo { get; set; }
public string Address { get; set; }
public string Owner { get; set; }
public int Size { get; set; }
public string Email { get; set; }
public int Phone { get; set; }
public int FaxNo { get; set; }
public string Password { get; set; }
public string Country { get; set; }
public string State { get; set; }

这是 ViewModel 代码

public CompanyFormViewModel() { }
public int? Id { get; set; }
[DisplayName(" Company Name")]
public string Name { get; set; }
[DisplayName("Owner")]
public string Owner { get; set; }
[DisplayName("Email")]
public string Email { get; set; }
[DisplayName("Password")]
public string Password { get; set; }
[DisplayName("Address")]
public string Address { get; set; }

这是DomainToViewModelMapping档案

cfg.CreateMap<Company, CompanyFormViewModel>()
    .ForMember(vm => vm.Id, map => map.MapFrom(m => m.Id))
    .ForMember(vm => vm.Name, map => map.MapFrom(m => m.Name))
    .ForMember(vm => vm.Owner, map => map.MapFrom(m => m.Owner))
    .ForMember(vm => vm.Email, map => map.MapFrom(m => m.Email))
    .ForMember(vm => vm.Password, map => map.MapFrom(m => m.Password))
    .ForMember(vm => vm.Address, map => map.MapFrom(m => m.Address));

我的viewModeltoDomainMapping配置文件

cfg.CreateMap<CompanyFormViewModel, Company>()
    .ForMember(m => m.Id, map => map.MapFrom(vm => vm.Id))
    .ForMember(m => m.Name, map => map.MapFrom(vm => vm.Name))
    .ForMember(m => m.Owner, map => map.MapFrom(vm => vm.Owner))
    .ForMember(m => m.Email, map => map.MapFrom(vm => vm.Email))
    .ForMember(m => m.Password, map => map.MapFrom(vm => vm.Password))
    .ForMember(m => m.Address, map => map.MapFrom(vm => vm.Address));
我为什么会收到“mapper未初始化”的错误?
3个回答

11

无法看到您初始化映射的位置。

解决方案:

您可以创建您的映射配置文件,例如:

public class MappingProfile : Profile
{
    public MappingProfile()
    {
       CreateMap<Company, CompanyFormViewModel>()
          .ForMember(vm => vm.Id, map => map.MapFrom(m => m.Id))
          .ForMember(vm => vm.Name, map => map.MapFrom(m => m.Name))
          .ForMember(vm => vm.Owner, map => map.MapFrom(m => m.Owner))
          .ForMember(vm => vm.Email, map => map.MapFrom(m => m.Email))
          .ForMember(vm => vm.Password, map => map.MapFrom(m => m.Password))
          .ForMember(vm => vm.Address, map => map.MapFrom(m => m.Address));
       CreateMap<CompanyFormViewModel, Company>()
          .ForMember(m => m.Id, map => map.MapFrom(vm => vm.Id))
          .ForMember(m => m.Name, map => map.MapFrom(vm => vm.Name))
          .ForMember(m => m.Owner, map => map.MapFrom(vm => vm.Owner))
          .ForMember(m => m.Email, map => map.MapFrom(vm => vm.Email))
          .ForMember(m => m.Password, map => map.MapFrom(vm => vm.Password))
          .ForMember(m => m.Address, map => map.MapFrom(vm => vm.Address)); 

    }
}

然后在 Global.asax.cs 中初始化映射配置文件。

    public class AutoMapperConfiguration
    {
        public static void Configure()
        {
            Mapper.Initialize(x =>
            {
                x.AddProfile<MappingProfile>();
            });

            Mapper.Configuration.AssertConfigurationIsValid();               
        }
    }

最后,别忘了在你的Application_Start()中配置自动映射器。

//Configure Automapper
AutoMapperConfiguration.Configure();

2
我承认这是一个晚回答,而且我对Automapper很新。之前也遇到过同样的错误。在寻找解决方案时发现了你的帖子。 - Salomon Zhang
1
我也是新手,所以想尝试一下使用AutoMapper来避免编写定制的映射类。如果我们必须手动配置每个属性,那么AutoMapper还有什么意义呢?它不能默认映射具有相同属性名称的两个对象吗? - Noobie3001
1
AutoMapper并不是100%的魔法。它不能映射具有不同名称的对象,但在某些情况下确实可以减少重复代码,从而有助于应用DRY原则。 - Salomon Zhang
谢谢回复。一切都好,我已经弄清楚如何正确设置并且按预期运行了。 - Noobie3001
在上述情况下,如果两个对象之间的所有属性名称都相同,您应该能够执行 CreateMap<Company, CompanyFormViewModel>() 并摆脱 ForMember - matcartmill
@matcartmill 是的,你说得对。对象具有相同名称不需要 ForMember。 - Salomon Zhang

5

不要使用静态的Mapper.Map方法,你需要使用通过配置创建的映射器实例,像下面这样:

var mapper = cfg.CreateMapper();
var company = (Company)mapper.Map(companyFormViewModel, company, typeof(CompanyFormViewModel), typeof(Company));

在最新版本中,处理映射器的首选方式是通过 IMapper 接口。如果您还在使用 DI 容器,可以将 IMapper 绑定/注册到 config.CreateMapper() 方法重载中,该重载接受实例工厂委托(即容器的实例工厂方法)以解决实例化。如果您不使用 DI 容器,您可以创建一个名为 MapperFactory 的类,负责映射器实例的创建和配置。
示例:
 var config = new MapperConfiguration(cfg =>
            {
                //cfg.CreateMap()...
                //cfg.AddProfile()... etc...
            });
var mapper = config.CreateMapper();

IMapperConfigurationExpression 不包含 CreateMapper() 的定义,也没有接受类型为 IMapperConfigurationExpression 的第一个参数的 CreateMapper 扩展方法... - mac
@mac 由于你没有展示出来,我假设您的 cfg 对象类型是 MapperConfiguration。然而,您需要实例化该类型的对象,在其中设置您的映射和配置文件,然后使用 CreateMapper 方法获取映射器实例。 - Darjan Bogdan
我按照你在例子中描述的方式更改了代码,但仍然遇到了相同的错误。 - mac
@mac 请参考文档,在那里您可以看到两种映射器初始化的方法(我向您展示的版本和如果您使用静态方法的版本)。 - Darjan Bogdan

1
你可能正在使用较旧版本的AutoMapper.Extensions.Microsoft.DependencyInjection 从NuGet安装最新版本的AutoMapper.Extensions.Microsoft.DependencyInjection(我使用的是v7.0.0),并在Startup.cs中将services.AddAutoMapper()更改为services.AddAutoMapper(typeof(services))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接