【问题标题】:AutoMapper mapping fails randomly when defining mappings locallyAutoMapper 映射在本地定义映射时随机失败
【发布时间】:2015-05-12 23:42:32
【问题描述】:

我们正在为我的 asp.net MVC/Web API 项目在方法定义中配置 automapper,如下所示。

public HttpResponseMessage GetDetails(int assignmentId)
{     
    var valuation = _valuationRepository.GetOneById(assignmentId);

    Mapper.CreateMap<UserLicenses, UserLicenseResponseModel>()
    .ForMember(dest => dest.State, opt => opt.MapFrom(src => src.States.StateCode))
    .ForMember(dest => dest.UserId, opt => opt.MapFrom(src => src.UserId))
    .ForMember(dest => dest.FullName, opt => opt.MapFrom(src => (src.UserProfile != null) ? (src.UserProfile.FirstName + ' ' + src.UserProfile.LastName) : " "));

    Mapper.CreateMap<AdditionalExpenses, AdditionalExpensesResponseModel>();
    Mapper.CreateMap<ValuationAssignment, ValuationAssignmentResponseModel>();

    var model = Mapper.Map<ValuationAssignmentResponseModel>(valuationAssignment);    
    return Request.CreateResponse(HttpStatusCode.OK, new  { Assignment = model });
}

我们注意到 api 随机不映射值,响应 json 为映射字段返回空值。

发生这种情况时,我正在回收应用程序池,它似乎可以工作一段时间,但我们又遇到了问题。

文档是指将所有映射存储在 Global.asax 中的 Application_Start 中。但是,我们在方法定义中设置它们 - 这就是我们看到这个问题的原因吗?

【问题讨论】:

  • 为什么需要为每个请求重新创建映射规则,而不是在应用启动时一次?
  • 谢谢杰森。如果我将它们放在 app_start 中,如何从存储库调用中注入/替换某些字段?
  • 我想我看到的方式是我们使用 AutoMapper 配置 ModelA 到 ModelA 的映射一次以供重用。如果我在每个请求中都自定义映射项,我最好放弃 AutoMapper 并在存储库或服务中进行手动映射,因为我并没有真正重用任何规则。你不能定义多重UserLicenses 规则吗? UserLiceses 到 X,UserLicenses 到 Y 等。如果这还不够可重用,您还可以映射到接口:UserLiceses 到 IUser 或 ILicense...此外,MapperCreateMap 是静态的,这可能就是您拥有的原因当您根据请求重新定义它们时出现问题。

标签: asp.net-web-api automapper


【解决方案1】:

问题在于 Web 应用程序是线程化的,而 Automapper 不是完全线程安全的。即有些方法和类是线程安全的,而另一些则不是。如果您使用静态类 Mapper,则可能会发生当一个线程尝试映射对象时,另一个线程尝试重新定义映射,这就是您得到这些随机错误的原因。

正如 Jasen 在他的评论中所说,以及您自己在您的问题中所说,一种解决方案是在一个中心位置定义所有映射,只定义一次,并且在执行第一个请求之前,通常在 Application_Start

另一种选择是使用 AutoMapper 中的非静态类。 IE。而不是使用Mapper 使用其他非静态类。这样,每个线程都有自己的实例,线程安全不是问题。有关该问题以及此替代解决方案的更多信息,另请参阅此问答:Is Mapper.Map in AutoMapper thread-safe?

顺便说一句,从性能的角度来看,最好只定义一次映射并重用它们,而不是一直重新定义它们。 AutoMapper 很可能使用反射,如果是这样,缓存类型和属性信息是非常可取的,以免降低性能。

【讨论】:

  • 将映射代码移至 Application_Start 后,我​​看不到回收应用程序池的必要性。我还实现了配置文件并一次加载它们。谢谢。
猜你喜欢
  • 2016-01-06
  • 2017-02-17
  • 1970-01-01
  • 2013-12-14
  • 1970-01-01
  • 1970-01-01
  • 2015-10-20
  • 2020-05-20
  • 1970-01-01
相关资源
最近更新 更多