AutoMapper and Autofac Revisited
What’s happened?
Back in September 2015 I posted about how we can simplify some of the pains within AutoMapper with a little help from Autofac – Getting along with AutoMapper and Autofac Since September 2015 there has been a release V4.2.0 on 28th January 2016 that broke the wiring within our inversion of control container setup, but don’t worry the changes are for the good and it seems like they’re going to kill off the evil statics members soon!
The new wiring
The new wiring is actually simpler as we need to know less about the internals of AutoMapper to construct the AutoMapper objects. To start with we need to create a MapperConfiguration
class that contains all our profiles and how our AutoMapper engine will be configured but instead of new’ing it up with lots of internal magic (new ConfigurationStore(new TypeMapFactory(), MapperRegistry.Mappers
) we just new-up a MapperConfiguration
passing in to the constructor an expression of how we want it configured:
var config = new MapperConfiguration(x =>
{
x.AddProfile(new MyProfile1());
x.AddProfile(new MyProfile2());
x.AddProfile(new MyProfile2());
});
Once we’ve got our MapperConfiguration
object all configured correctly, all we need to do is call the CreateMapper()
function on the MapperConfiguration
instance.
var mapper = config.CreateMapper();
var obj1 = new ClassA();
var obj2 = mapper.Map<ClassB>(obj1);
As you can see above we then just get back an IMapper (not an IMappingEngine) and can call the normal Mapping methods. More simple than you thought right?
Autofac me
Now we know how to couple up all of our object to create our IMapper
let’s put this in to an Autofac module.
public class AutoMapperModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register(context =>
{
var profiles = context.Resolve<IEnumerable<Profile>>();
var config = new MapperConfiguration(x =>
{
// Load in all our AutoMapper profiles that have been registered
foreach (var profile in profiles)
{
x.AddProfile(profile);
}
});
return config;
}).SingleInstance() // We only need one instance
.AutoActivate() // Create it on ContainerBuilder.Build()
.AsSelf(); // Bind it to its own type
// HACK: IComponentContext needs to be resolved again as 'tempContext' is only temporary. See http://stackoverflow.com/a/5386634/718053
builder.Register(tempContext =>
{
var ctx = tempContext.Resolve<IComponentContext>();
var config = ctx.Resolve<MapperConfiguration>();
// Create our mapper using our configuration above
return config.CreateMapper();
}).As<IMapper>(); // Bind it to the IMapper interface
base.Load(builder);
}
}
We can also replace the above:
config.CreateMapper();
With
config.CreateMapper(t => ctx.Resolve(t));
This will make Autofac be in control of all object creation within your AutoMapper profiles which is useful for external dependencies, object disposal and mocking.