Calling IMappingEngine.Map inside custom mapping

2019-04-09 14:25发布

With AutoMapper, when using ConvertUsing to define a custom mapping for a type that is a container, I often need to call IMappingEngine.Map inside the mapping function. This is necessary because it allows-me to reuse the definition of the child mapping.

CreateMap<Order, OrderModel>()
    .ConvertUsing(o => new OrderModel(
        o.Id,
        o.ShippingAddress,
        mapper.Map<IList<OrderItemModel>>(o.Items)
    ));

In order to do this, I need a reference to IMappingEngine. When the mapping engine is being configured, I don't have a reference to it that can be captured in the ConvertUsing argument. A simple solution is to have a static reference to it somewhere, but I would like to avoid it.

Is there a way to get a reference to the current IMappingEngine inside a mapping that uses ConvertUsing?

2条回答
冷血范
2楼-- · 2019-04-09 14:40

You can use the static Mapper.Map<IList<OrderItemModel>>(o.Items) instead of your instance of IMappingEngine. It contains a reference to the engine that is lazily instantiated the first time it is used.

查看更多
趁早两清
3楼-- · 2019-04-09 14:48

This answer is based on your original revision which included additional code

If you take a look at the article by Jimmy Bogard on Automapper and IOC he notes the following:

The MappingEngine, unlike our Configuration object, does not need any special caching/lifetime behavior. The MappingEngine is very lightweight, as it’s really a bunch of methods doing interesting things with Configuration. MappingEngine can be singleton if we want, but there’s no need.

(There is updated sample IOC code for the latest version of Automapper on github)

As long as your ConfigurationStore is a singleton and requests for IConfiguration and IConfigurationProvider from your DI container resolve to this singleton instance, the article (and code examples) advocates that is fine to create new instances of the MappingEngine when injected.

Based on the above, aside from not registering your ConfigurationStore as a singleton instance (I assume, I'm not familiar with ninject) and not binding this instance to the IConfiguration your final implementation of MappingProfile in your original revision is actually an acceptable solution. It is OK for this to not be the same MappingEngine instance.

However, going by your sample usage in your question it may be worth considering Scenario 2 in the article. If you have no requirement to inject configuration throughout your application and only the IMappingEngine, then you can rely on the static Mapper class for the configuration and lifetime management. In summary your changes to adopt this would be:

  1. Remove the IConfigurationProvider related wiring in the build-up of your container (in the MappingModule).

  2. Switching your MappingProfile to use the static Mapper class

    CreateMap<Order, OrderModel>()
        .ConvertUsing(o => new OrderModel(
            o.Id,
            o.ShippingAddress,
            Mapper.Map<IList<OrderItemModel>>(o.Items) //use static Mapper class
    ));
    
    CreateMap<OrderItem, OrderItemModel>();
    
  3. Adding the Profile to the Mapper (perhaps in the MappingModule?), and doing any other configuration through the Mapper:

    Mapper.AddProfile(new MappingProfile());
    
  4. Binding IMappingEngine in the ninject container to the Mapper.Engine property.

查看更多
登录 后发表回答