Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AutoMapper How To Map Object A To Object B Differently Depending On Context

Tags:

c#

automapper

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 certain properties in one mapping case, and have all properties mapped in another case.

What I'm experiencing is that Mapper.CreateMap can be called successfully in the different mapping cases however, once CreateMap is called, the map for a particular pair of types is set and is not subsequently changed by succeeding CreateMap calls which might describe the mapping differently.

I found a blog post which advocates Mapper.Reset() to get round the problem, however, the static nature of the Mapper class means that it is only a matter of time before a collision and crash occur.

Is there a way to do this?

What I think I need is to call Mapper.CreateMap once per appdomain, and later, be able to call Mapper.Map with hints about which properties should be included / excluded.

Right now, I'm thinking about changing the source code by writing a non-static mapping class that holds the mapping config instance based. Poor performance, but thread safe.

What are my options. What can be done? Automapper seems so promising.

like image 475
IanT8 Avatar asked Apr 29 '10 00:04

IanT8


2 Answers

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);
like image 116
Eli Algranti Avatar answered Oct 01 '22 04:10

Eli Algranti


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.

like image 37
Jimmy Bogard Avatar answered Oct 01 '22 03:10

Jimmy Bogard