I'm looking up AutoMapper code now (evaluating it for one of projects I'm working on), and, frankly speaking, I'm quite surprised:
- The library API is based on a single static access point (
Mapper
type), so generally any of its methods must be thread safe
- But I didn't find ANY evidence of this in code.
All I was able to find is this issue, but even the statement made there seems incorrect: if Map
doesn't use thread-safe data structures internally, it can't be considered as thread-safe as well, if I'm going to call CreateMap
in non-concurrent context, but concurrently with Map
.
I.e. the only possible usage pattern of AutoMapper in e.g. ASP.NET MVC application is:
lock (mapperLock) {
... Mapper.AnyMethod(...) ...
}
Obviously, if I'm correct, that's a huge lack.
So I have two questions:
- Am I correct?
- If yes, what's the best alternative to AutoMapper that doesn't have this issue?
The linked issue more or less answers your questions:
Mapper.CreateMap is not threadsafe, nor will it ever be. However,
Mapper.Map is thread-safe. The Mapper static class is just a thin
wrapper on top of the MappingEngine and Configuration objects.
So only use Mapper.CreateMap
if you do your configuration in one central place in a threadsafe manner.
Your comment was:
I'm asking this because I'd like to configure automatter in-place,
i.e. right before usage. I planned to configure it in non-concurrent
context, i.e. ~ lock (mapperConfigLock) { Mapper.CreateMap()....; },
and I fear this is not enough now.
If you are doing in-place configuration just don't use the static Mapper
class. As the comment on the github issue suggest use the mapping engine directly:
var config =
new ConfigurationStore(new TypeMapFactory(), MapperRegistry.AllMappers());
config.CreateMap<Source, Destination>();
var engine = new MappingEngine(config);
var source = new Source();
var dest = engine.Map(source);
It's a little bit of more code but you can create your own helpers around it.
But everything is local in a given method so no shared state no need to worry about thread safety.
This questions may be a little bit outdated, just want to record some of my findings after a little bit of investigation.
Mapper is a wrapper class to wrap to create new configuration, and new instance of mapper inside static memory, so strictly speaking it is not thread-safe, but you can use it safe as long as you only initialize the configuration once.
MapperConfiguration create new instance of mapper, and record the config inside its own instance memory space.
TLDR;
If you need to init the configuration ONCE only, choose the static API
If you need to init the configuration many times, and worry about the the thread safety, choose instance API