Using AutoMapper to match Wrapper <T> to T 'by convention

I have a service that wraps enum values ​​in a SafeEnum type to enable the addition of new enum values ​​without breaking contract.

Here's an example:

public class Customer
{
  public int Id { get; set; }
  public SafeEnum<CustomerType> Type { get; set; }
}

public class CustomerModel
{
  public int Id { get; set; }
  public CustomerModelType Type { get; set; }
}

      

When mapping a customer to a CustomerModel using AutoMapper, is there a way to automatically map from SafeEnum<T>

to T'

, where T

is the wrapped type, and T'

is the match type in the model?

I know this can be fixed by setting up an enum type for each appropriate type, but I am looking for a more elegant solution.

+3


source to share


1 answer


I recently faced the same problem. From what I have gathered, there is no official support from Automapper for such a scenario (there is no mention of generic shells or anything similar in the documentation, and I couldn't find any web resource how to do it), but it can do with a little work.

First, you need to create a class that implements the interface IObjectMapper

. This interface has two methods: IsMatch(ResolutionContext context)

andMap(ResolutionContext context, IMappingEngineRunner mapper)

When mapping two objects, the method is IsMatch

used internally by Automapper to determine if a given instance can be IObjectMapper

used to map from source to destination type. On an object ResolutionContext

, you have a SourceType, DestinationType, SourceValue, DestinationValue, a MappingEngine instance, among others, which can help you determine if you can map the two types to your current mapper.

The Map method is responsible for the actual mapping between the two types.

So, by method, IsMatch

you have to check if source or target types are instances of your wrapper class. And then, by method Map

, when matching the wrapped value, you can expand the value with reflection and use the display mechanism provided in the permission to map the expanded value to its destination type and then return it.

Likewise, when mapping any type to a wrapped type, you can get the type argument of the private shared wrapper, use the mapping mechanism provided in the resolution context to map from the source type to the type enclosed in your generic wrapper, and wrap the result on an instance of the appropriate wrapper class type.



Finally, you need to enable this handler when configuring the MappingEngine at application startup (this does not work with the static method of the Mapper class, since you cannot change it from the default), for example

var configuration = new ConfigurationStore(new TypeMapFactory(), new IObjectMapper[] { new WrapperMapper()}.Union(MapperRegistry.Mappers));
        var engine = new MappingEngine(configuration);    

      

A static property MapperRegistry.Mappers

is a collection of all Automapper default machines. If you don't enable them, you will lose all default functionality.

Finally a fiddle works here: https://dotnetfiddle.net/vWmRiY

It will probably take some work to adapt it to your specific use case, but the general idea is there. This can be used to wrap primitive types, complex types, or anything supported by the automapper.

0


source







All Articles