Calling all AutoMapper gurus!
I\'d like to be able to map object A to object B differently depending on context at runtime. In particular, I\'d like to ignore certai
The Mapper class is merely a thin wrapper on top of a Configuration and MappingEngine objects. You can create separate instances of Configuration/MappingEngine objects (still using singletons), and use your IoC container of choice to load the correct one as necessary.
The best option still is to use different destination types. The really tough part about truly supporting this feature is the inherent hierarchical nature of type maps. The top-level object might have a mapping profile, while lower level ones do not. Some in between might have it or not, etc.
To me, it sounds like a better design might be to have multiple destination classes (possibly inheriting from a common base or implementing a common interface)
If the unmapped properties will never be used in one of the variations, you could leave them out entirely (giving compile time guarantee that they aren't used by mistake), throw an exception when they are accessed (not as good as a compile time guarantee, but sometimes you need the full interface to be implemented) or even use a substitute value.
For example:
public class Source
{
public string Name {get;set;}
public BigEntity {get;set;}
/* other members */
}
public class SourceDTO
{
public string Name {get;set;}
public BigEntity {get;set;}
}
public class SourceSummaryDTO
{
public string Name {get;set;}
}
Alternatively, you could do this:
public class SourceSummaryDTO : SourceDTO
{
public string Name {get;set;}
public BigEntity
{
get{throw new NotSupportedException();}
set{throw new NotSupportedException();}
}
}
That way, you could pass a SourceSummaryDTO as if it was a SourceDTO.
Having properties conditionally populated sounds like a recipe for trouble to me - I'd rather have classes that are explicit about what they contain, especially with Data Transfer objects.
For me, the best thing about Automapper is the ability to verify the mappings and then know that every property on destination classes will be populated.
Just to complement Jimmy's answer here's the code needed to use AutoMapper without the static Mapper
As of version 4.2.1 Automapper has a sanctioned non static mapper and configuration (thanks Jimmy!).
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<ClassA, ClassB>();
});
var mapper = config.CreateMapper();
There are many other useful options (such as profiles) in the new releases for creating different mapper instances. You can get all the details in the official documentation
(correct for version 4.1.1)
// Configuration
AutoMapper.Mappers.MapperRegistry.Reset();
var autoMapperCfg = new AutoMapper.ConfigurationStore(new TypeMapFactory(), AutoMapper.Mappers.MapperRegistry.Mappers);
var mappingEngine = new AutoMapper.MappingEngine(autoMapperCfg);
autoMapperCfg.Seal();
//Usage example
autoMapperCfg.CreateMap<ClassA, ClassB>();
var b = mappingEngine.Map<ClassB>(a);
(correct for version 3.2.1)
// Configuration
var platformSpecificRegistry = AutoMapper.Internal.PlatformAdapter.Resolve<IPlatformSpecificMapperRegistry>();
platformSpecificRegistry.Initialize();
var autoMapperCfg = new AutoMapper.ConfigurationStore(new TypeMapFactory(), AutoMapper.Mappers.MapperRegistry.Mappers);
var mappingEngine = new AutoMapper.MappingEngine(autoMapperCfg);
//Usage example
autoMapperCfg.CreateMap<ClassA, ClassB>();
var b = mappingEngine.Map<ClassB>(a);
(correct for version 2.2.1)
// Configuration
var autoMapperCfg = new AutoMapper.ConfigurationStore(new AutoMapper.TypeMapFactory(), AutoMapper.Mappers.MapperRegistry.AllMappers());
var mappingEngine = new AutoMapper.MappingEngine(autoMapperCfg);
//Usage example
autoMapperCfg.CreateMap<ClassA, ClassB>();
var b = mappingEngine.Map<ClassB>(a);