1

I've never encountered this odd behavior before from Automapper. To begin with, I'm using Automapper 3.3.0, and Entity Framework 6.1.3. I have a method that retrieves entity data via entity framework. Prior to returning the data, it is mapping it to a domain model. With the exception of three (3) of the properties, the names of pertinent properties match between entity and domain, thus you will see in the sample code that I provide that there are simply three (3) ForMember calls when creating the map.

This works fine most of the time, as I would expect it should. However, occasionally, and I can't for the life of me nail down the exact steps to repro, the mapping succeeds with the exception of the three (3) explicitly mapped properties.

Here's the code that I believe is pertinent:

var dailyPriceHistories = 
  MapToDomain(_clearDbEntities.get_DailyPriceHistory(startDate.Date, endDate.Date).ToList());

FYI, the ToList call is intended to prevent lazy loading problems from EF.

And, the mapper:

private static IList<DailyPriceHistory> MapToDomain(List<get_DailyPriceHistory_Result> someDataEntities)
{
    Mapper.CreateMap<get_DailyPriceHistory_Result, DailyPriceHistory>()
        .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.DailyPriceHistory_ID))
        .ForMember(dest => dest.ProductId, opt => opt.MapFrom(src => src.AllProducts_ID))
        .ForMember(dest => dest.DateInfoId, opt => opt.MapFrom(src => src.DateInfo_ID));

    return Mapper.Map<List<get_DailyPriceHistory_Result>, List<DailyPriceHistory>>(dailyPriceHistoryEntities);
}

If I do an iisreset, everything is fine, it works again. It seems to occur when I've gone back and forth a bit with debug mode in Visual Studio 2013. It's like it just forgets how to map those properties. The entity data being passed in does always contain the values, by the way, it simply fails to map the three of them to the domain.

Any help would be greatly appreciated. Thanks!

Jim Speaker
  • 1,303
  • 10
  • 28
  • First put the map creation in the application startup. It should be done once. I don't know the effect of multiple threads executing `Mapper.CreateMap` simultaneously. – Gert Arnold Aug 09 '15 at 18:58
  • Ok, I'll give that a rip. Being a static method I was under the understanding that the map would be created just once. Is my understanding of this incorrect? Oh... no... I see now that of course the CreateMap call occurs every time. I'm going to move the CreateMap call as you suggested, and simply invoke it in my private static method. – Jim Speaker Aug 09 '15 at 19:01
  • @GertArnold I've dug into the AutoMapper code and `Mapper.CreateMap` is not thread safe. @Jim Speaker if you are calling `Mapper.CreateMap` in multiple locations things will break in strange ways like you are seeing. You're mappings all need to be created *before* you start using the `Mapper`. Also you are thinking of static constructors that are only run once. Static methods run each time you call them. – shf301 Aug 09 '15 at 19:07
  • @shf301 Yes, I was thinking of static constructors. It took just a minute to go, "D'OH!" and see the error of my ways. I'm refactoring right now to move all my CreateMap calls into a static class and method called by Application_Start. – Jim Speaker Aug 09 '15 at 19:09
  • Refactored. The problem isn't rearing it's ugly head yet, but sometimes it takes a bit for it to occur. Thank you both, I used Automapper pretty extensively at my previous job awhile back, but I'd simply forgotten that indeed all the mappings were being done once in the fairly mature api framework that I was developing in. Some PE had set that up, so its importance was sorta lost on me. Thanks again. Oh, and if one of you wants to write up the answer, I'd be very happy to accept it. Cheers – Jim Speaker Aug 09 '15 at 19:25

1 Answers1

4

Mapper.CreateMap is not thread-safe (nor was ever really intended to be). You should only be creating your maps once at startup, typically kicked off for ASP.NET apps in App_Start in Global.asax.

Jimmy Bogard
  • 26,045
  • 5
  • 74
  • 69