Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AutoMapper Threading Issue (Missing type map configuration or unsupported mapping)?

I'm not sure if I have a threading issue here or not. On the page load I am executing two Ajax requests to load some additional data from a third party API. Here is what each method looks like that gets called:

private List<CaseCommentModel> GetCaseCommentModels(string caseId) {
    var comments = CaseService.GetAllCaseCommentsByCaseId(caseId);

    Mapper.Reset();
    Mapper.CreateMap<CrmCaseComment, CaseCommentModel>();

    var caseCommentModels = Mapper.Map<List<CrmCaseComment>, List<CaseCommentModel>>(comments);

    return caseCommentModels;
}

private List<CaseAttachmentModel> GetCaseAttachmentModels(string caseId) {
    var attachments = AttachmentService.GetAttachmentsByParentId(caseId);

    Mapper.Reset();
    Mapper.CreateMap<CrmAttachment, CaseAttachmentModel>();

    var caseAttachmentModels = Mapper.Map<List<CrmAttachment>, List<CaseAttachmentModel>>(attachments);

    return caseAttachmentModels;
}

Sometimes both responses succeed. But, if I refresh the page, sometimes one will fail with the following exception:

Missing type map configuration or unsupported mapping

I can go from both requests succeeding to one failing without making any code changes; all it takes is a refresh of the page. Is this a threading issue or am I using the mapper incorrectly?

like image 631
Justin Helgerson Avatar asked Mar 23 '12 18:03

Justin Helgerson


3 Answers

Yes, you have a threading issue and you are misusing the Automapper configuration. From the Automapper getting started page:

If you're using the static Mapper method, configuration only needs to happen once per AppDomain. That means the best place to put the configuration code is in application startup, such as the Global.asax file for ASP.NET applications. Typically, the configuration bootstrapper class is in its own class, and this bootstrapper class is called from the startup method.

So you shouldn't have Mapper.CreateMap inside the controller actions move them to common place and execute them once.

Or if you do need dynamic mapping configuration don't use the static Mapper instead of build the config and the engine "by hand":

var config = 
    new ConfigurationStore(new TypeMapFactory(), MapperRegistry.AllMappers());
config.CreateMap<CrmCaseComment, CaseCommentModel>();
var engine = new MappingEngine(config);
var caseCommentModels = 
    engine.Map<List<CrmCaseComment>, List<CaseCommentModel>>(comments);
like image 58
nemesv Avatar answered Sep 28 '22 09:09

nemesv


You should Create a Mapping only once per application life time. So, move each specific CreateMap to app start.

The problem you are experiencing is probably related to the race to do the mapping before the other thread calls Mapper.Reset()

like image 23
dotjoe Avatar answered Sep 28 '22 08:09

dotjoe


I came across a threading issue and would like to share my findings.

In my application in the WCF Service Constructor I called the AutoMapperRegistry. Configure () to create the Mappings for the auto mapper.

From the MVC controller I call the service by calling the singleton object of the WCF service.

The actual issue is from the web client I actually called asyncrounusly two of the controller methods so that both communicated to the service and returns the result. The moment i changed the first method to Async false in the problem was resolved.

Reason When both methods are called async the race condition occurs and once in a while that is resolved by it self sometimes this threading issue is created as a result the above exception is thrown.

like image 38
Desmond Avatar answered Sep 28 '22 08:09

Desmond