theDmi
theDmi

Reputation: 18034

How to reuse ValueResolver across different mappings in AutoMapper 5?

I just tried upgrading AutoMapper to 5.0.2 but hit a road block.

According to the migration docs, value resolvers have now access to the destination object:

The signature of a value resolver has changed to allow access to the source/destination models.

This has the consequence that each value resolver is tied to exactly one destination type.

However, some of our value resolvers are used for multiple destination types. We have e.g. a resolver that is used during the mapping of all the ID properties of our DTOs. The resolver modifies the ID by means of a service that is injected into the resolver.

How would I define reusable value resolvers in AutoMapper 5, so that I don't have to create dedicated resolvers for each destination type with exactly the same implementation?

Note: The main reason to use a value resolver instead of directly manipulating the values is dependency injection. As per this answer, value resolvers are the best way to use a dependency-injected service during the mapping.

Upvotes: 2

Views: 2225

Answers (2)

yaddly
yaddly

Reputation: 360

Good day, I think the best way would be to use Generics as follows:

public class FooResolver<TSource, TDestination> : IValueResolver<TSource, TDestination, string>
{
   private readonly Dictionary<Type, int> typeDictionary;

   public FooResolver()
   {
      typeDictionary = new  Dictionary<Type, int>
     {
        {typeof(FooA), 0},
        {typeof(FooB), 1}
     };
   }

   pulic string Resolve(TSource source, TDestination destination, string destMember, 
   ResolutionContext context)
   {
      switch (typeDictionary[source.GetType()])
      {
         case 0:
           var fooA = ((FooA)Convert.ChangeType(source, typeof(FooA)));
           //custom code
         break;
         case 1:
           var fooB = ((FooB)Convert.ChangeType(source, typeof(FooB)));
           //custom code
         break;
      }

      return string_value;
   }
}

During Mapping you simply provide the actual types for source and destination e.g. act.MapFrom<FooResolver<FooA, FooADestination>>

Upvotes: -1

Jimmy Bogard
Jimmy Bogard

Reputation: 26765

The destination type can just be "object":

public class FooResolver : IValueResolver<object, object, string> {}

Or it can be more specific:

public class FooResolver : IValueResolver<IEntity, object, string> {}

Because of the variance defined for IValueResolver, you can put base types in the first two generic arguments.

Upvotes: 5

Related Questions