2

I want to use DI whenever I call automapper so that I can uncouple some of my layers. Instead of calling automapper like this:

 public class MyController : Controller 
 {

     public ActionResult MyAction(MyModel model)
     {
          var newModel= Mapper.Map<MyModel, NewModel>(model);
          return View(model);
      }
  }

I want to do this:

  public class MyController : Controller 
 {

     IMappingEngine _mappingEngine;

     public MyController(IMappingEngine mappingEngine)
     {   
        _mappingEngine = mappingEngine;
     }

     public ActionResult MyAction(MyModel model)
     {
          var newModel= _mappingEngine.Map<MyModel, NewModel>(model);
          return View(model);
      }
  }

I am using Ninject as my IOC. How do I bind an interface to it though?

I also need to mention that I am using Profiles and already have:

var profileType = typeof(Profile);
        // Get an instance of each Profile in the executing assembly.
        var profiles = Assembly.GetExecutingAssembly().GetTypes()
            .Where(t => profileType.IsAssignableFrom(t)
                && t.GetConstructor(Type.EmptyTypes) != null)
            .Select(Activator.CreateInstance)
            .Cast<Profile>();

        // Initialize AutoMapper with each instance of the profiles found.
        Mapper.Initialize(a => profiles.ForEach(a.AddProfile));

I know that the step I am missing involves binding to the kernal:

kernel.Bind<IMappingEngine>.To<>(); //I do not know what
//to bind it to here so that when I call IMappingEngine;
//It will trigger my maps from my automapper profiles.
BatteryBackupUnit
  • 12,934
  • 1
  • 42
  • 68
Robert
  • 4,306
  • 11
  • 45
  • 95

1 Answers1

2

I can't seem to find IMappingService in the AutoMapper repository (https://github.com/AutoMapper/AutoMapper/search?q=IMappingService). However, there is a IMappingEngine.

All you've got to do is

IBindingRoot.Bind<IMappingEngine>().ToMethod(x => Mapper.Engine);

or

IBindingRoot.Bind<IMappingEngine>().To<MappingEngine>();
IBindingRoot.Bind<IConfigurationProvider>().ToMethod(x => Mapper.Engine.ConfigurationProvider);

and you're good to go.

Remember, however, that the first access to Mapper.Engine or Mapper.ConfigurationProvider will initialize AutoMapper.

So without the binding, AutoMapper get's initialized the first time you do something like Mapper.Map<,>. With the binding it will get initialized the first time an object is constructed which gets IMappingEngine injected.

If you want to retain the previous initialization behavior there are a few choices:.

  • a) Instead of injecting IMappingEngine inject Lazy<IMappingEngine> instead (i think this requires the ninject.extensions.factory extension)
  • b) bind IMappingEngine to a proxy (without target). The proxy should access the Mapper.Engine only when .Intercept(...)ing a method. Also it should forward the method calls.
  • c) write your own LazyInitializedMappingEngine : IMappingEngine implementation which does nothing than forward every method to Mapper.Engine.

i would probably go with c), the others are too much work. c) will require code adaption whenever the interface of IMappingEngine changes. b) would not but is more complicated and slower. a) is bleeding through to all consumers of the interface and easily to get wrong once in a while, breaking stuff and a bit hard to trace back, so i would refrain from it, too.


c):

public class LazyInitializedMappingEngine : IMappingEngine
{
    public IConfigurationProvider ConfigurationProvider { get { return Mapper.Engine.ConfigurationProvider; } }

    public TDestination Map<TDestination>(object source)
    {
        return Mapper.Map<TDestination>(source);
    }

    public TDestination Map<TDestination>(object source, Action<IMappingOperationOptions> opts)
    {
        return Mapper.Map<TDestination>(source, opts);
    }

    public TDestination Map<TSource, TDestination>(TSource source)
    {
        return Mapper.Map<TSource, TDestination>(source);
    }

    //... and so on ...
}

kernel.Bind<IMappingEngine>().To<LazyInitializedMappingEngine>();
BatteryBackupUnit
  • 12,934
  • 1
  • 42
  • 68
  • I realize I am late in asking about this but I was laid off from the job that I was at when I asked this. Could you give an example of Option C. I am not sure what you mean by "forward" to mapper.Engine – Robert Jul 18 '14 at 20:26
  • @Robert, i'm sorry to hear that. Hope you'll get a new job - a good one - soon! I'll post the example. – BatteryBackupUnit Jul 21 '14 at 05:48