开发者

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开发者_Python百科 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?


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();
}


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)
    {
    }
}


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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜