Brendan Vogt
Brendan Vogt

Reputation: 26028

Generic mapper instead of having numerous individual mappers

I am using ASP.NET MVC 3 with Razor and Autofac for dependency injection.

I am thinking of creating a generic mapper. Currently I am using AutoMapper for the mapping between my domain and view model. It can be any mapping framework, but I am using AutoMapper .

Here is my IMapper interface:

public interface IMapper
{
     object Map(object source, Type sourceType, Type destinationType);
}

I then have an IBankMapper interface that implements this IMapper interface. The reason why I did it like this is because I can have many different mappers. Using dependency injection I can know what instance I can inject. So for IBankMapper I will inject BankMapper, ICategoryMapper I will inject CategoryMapper.

IBankMapper interface:

public interface IBankMapper : IMapper
{
}

BankMapper class:

public class BankMapper : IBankMapper
{
     static BankMapper()
     {
          Mapper.CreateMap<Bank, EditBankViewModel>();
          Mapper.CreateMap<EditBankViewModel, Bank>();
     }

     public object Map(object source, Type sourceType, Type destinationType)
     {
          return Mapper.Map(source, sourceType, destinationType);
     }
}

As the program grows so will the mapper classes. Is there a way that I can create a generic mapper, one that can be used in the whole application? Is this possible?

Upvotes: 2

Views: 2984

Answers (3)

jeroenh
jeroenh

Reputation: 26782

As Daniel said, Automapper is already a generic mapper. If you're worried about the direct dependency to automapper in your code, you can hide it behind a little facade, e.g.:

public interface IMapper
{
    TDestination Map<TSource, TDestination>(TSource source);
}
public class MyMapper :IMapper
{
    public TDestination Map<TSource, TDestination>(TSource source)
    {
        AutoMapper.Mapper.CreateMap<TSource, TDestination>();
        return AutoMapper.Mapper.Map<TSource, TDestination>(source);
    }
}

This can also help you to model the mapper as an injectable dependency

Upvotes: 1

Justin Niessner
Justin Niessner

Reputation: 245429

There is absolutely no need for you to create any mapper classes at all.

All you need to do is be sure that you call Mapper.CreateMap at the beginning of your application. You can then use Mapper.Map to do your mapping.

Typically, I create a static class with a single method to handle the creation of my Maps. It looks something like:

public static class Transformers
{
    public static void Register()
    {
        Mapper.CreateMap<Bank, EditBankViewModel>();
        Mapper.CreateMap<EditBankViewModel, Bank>();

        Mapper.CreateMap<Account, EditAccountViewModel>();
        Mapper.CreateMap<EditAccountViewModel, Account>();

        // And so on. You can break them up into private methods
        // if you have too many.
    }
}

I then call that method inside Global.asax do ensure that it runs when necessary. In any other spot in my application, I'm free to call Mapper.Map for any of the configured mappings:

protected void Application_Start()
{
    Transformers.Register();
}

Upvotes: 5

Daniel Hilgarth
Daniel Hilgarth

Reputation: 174319

It looks like you are creating these interfaces to be able to mock AutoMapper in your unit tests. You can simply use IMappingEngine from AutoMapper for this purpose.

Your classes would have a dependency on IMappingEngine which would be injected. IMappingEngine has the same methods as the static class Mapper to map your objects.

In your composition root you would configure the mapper and register the mapping engine with the DI container.

Something like this:

// composition root:
Mapper.CreateMap<Bank, EditBankViewModel>();
Mapper.CreateMap<EditBankViewModel, Bank>();
builder.Register(Mapper.Engine);

// your classes:
class YourClass
{
    public YourClass(IMappingEngine mappingEngine)
    {
    }
}

Upvotes: 4

Related Questions