Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Autofac 3 and Automapper

Does anyone know of a comprehensive guide to setting up Automapper with Autofac. I'm new to both but I have played around with the static Mapper class however I want to be able to mock and inject IMappingEngine and create a configuration that sets up all my mappings. All the guides I have looked at so far don't really explain what is going on and I can't quite work it out. Also I am using Autofac 3.0 which seems to have some differences in the ContainerBuilder methods which doesn't help (the reason I'm using it is that Autofac.mvc4 depends on it).

Update:

OK, the simplest solution seems to work well enough, however I had not seen it anywhere on the internet and that maybe for a good reason that I don't know? The simplest thing to do is just to Register the static Mapper.Engine as IMappingEngine and still use the static Mapper.CreateMap to configure in the first place.

var builder = new ContainerBuilder();
builder.Register<IMappingEngine>(c => Mapper.Engine);

Now Autofac can inject the IMappingEngine into your constructors. This does mean that Mapper will handle the IMappingEngine singleton rather than Autofac and Autofac is just acting as a wrapper for it. I would like Autofac to handle the IMappingEngine instance but I'm not sure how?

like image 308
shmish111 Avatar asked Dec 27 '22 10:12

shmish111


1 Answers

Your simple solution is OK provided that you don't want to mock the mapper in unit tests or create mappers with modified configurations for nested lifetime scopes (the latter one looks a bit weird to me, but who knows).

If you need that, you can pick up some pieces of code from the Mapper class and register components like this:

builder.Register(ctx => new ConfigurationStore(new TypeMapFactory(), MapperRegistry.AllMappers()))
       .AsImplementedInterfaces()
       .SingleInstance();

builder.RegisterType<MappingEngine>()
       .As<IMappingEngine>();

I'm not sure if you really need to make IMappingEngine a singleton. It should be quite lightweight to create per dependency.

Now you can use it like this:

// in a bootstrapper:
var mapperConfig = ctx.Resolve<IConfiguration>();
mapperConfig.CreateMap<A, B>();

// later on:
public class X{
    IMappingEngine _mapper;

    public X(IMappingEngine mapper){
        _mapper = mapper;
    }

    public B DoSmth(){
        return _mapper.Map<B>(new A());
    }
}

You can also set up automatic profiles registration like this:

builder.Register(ctx => new ConfigurationStore(new TypeMapFactory(), MapperRegistry.AllMappers()))
       .AsImplementedInterfaces()
       .SingleInstance()
       .OnActivating(x => {
           foreach (var profile in x.Context.Resolve<IEnumerable<Profile>>()){
               x.Instance.AddProfile(profile);
           }
       });

Then just register a Profile implementation anywhere in Autofac configuration or in a module to get it hooked up to the configuration.

like image 70
Pavel Gatilov Avatar answered Feb 27 '23 08:02

Pavel Gatilov