Custom Value Resolvers

Although AutoMapper covers quite a few destination member mapping scenarios, there are the 1 to 5% of destination values that need a little help in resolving. Many times, this custom value resolution logic is domain logic that can go straight on our domain. However, if this logic pertains only to the mapping operation, it would clutter our source types with unnecessary behavior. In these cases, AutoMapper allows for configuring custom value resolvers for destination members. For example, we might want to have a calculated value just during mapping:

public class Source
{
	public int Value1 { get; set; }
	public int Value2 { get; set; }
}

public class Destination
{
	public int Total { get; set; }
}

For whatever reason, we want Total to be the sum of the source Value properties. For some other reason, we can't or shouldn't put this logic on our Source type. To supply a custom value resolver, we'll need to first create a type that implements IValueResolver:

public interface IValueResolver
{
	ResolutionResult Resolve(ResolutionResult source);
}

The ResolutionContext contains all of the contextual information for the current resolution operation, such as source type, destination type, source value and so on. For most scenarios, we won't need this more advanced interface. Instead, we can derive from the ValueResolver<TSource, TDestination> abstract class:

public class CustomResolver : ValueResolver<Source, int>
{
	protected override int ResolveCore(Source source)
	{
		return source.Value1 + source.Value2;
	}
}

Once we have our IValueResolver implementation, we'll need to tell AutoMapper to use this custom value resolver when resolving a specific destination member. We have several options in telling AutoMapper a custom value resolver to use, including:
  • ResolveUsing<TValueResolver>
  • ResolveUsing(typeof(CustomValueResolver))
  • ResolveUsing(aValueResolverInstance)
In the below example, we'll use the first option, telling AutoMapper the custom resolver type through generics:

Mapper.CreateMap<Source, Destination>()
	.ForMember(dest => dest.Total, opt => opt.ResolveUsing<CustomResolver>());
Mapper.AssertConfigurationIsValid();

var source = new Source
	{
		Value1 = 5,
		Value2 = 7
	};

var result = Mapper.Map<Source, Destination>(source);

result.Total.ShouldEqual(12);

Although the destination member (Total) did not have any matching source member, specifying a custom resolver made the configuration valid, as the resolver is now responsible for supplying a value for the destination member.

Custom constructor methods

Because we only supplied the type of the custom resolver to AutoMapper, the mapping engine will use reflection to create an instance of the value resolver.

If we don't want AutoMapper to use reflection to create the instance, we can either supply the instance directly, or use the ConstructedBy method to supply a custom constructor method:

Mapper.CreateMap<Source, Destination>()
	.ForMember(dest => dest.Total, 
		opt => opt.ResolveUsing<CustomResolver>().ConstructedBy(() => new CustomResolver())
	);

AutoMapper will execute this callback function instead of using reflection during the mapping operation, helpful in scenarios where the resolver might have constructor arguments or need to be constructed by an IoC container.

Customizing the source value supplied to the resolver

Coming soon

Custom value resolution expressions

Coming soon

Last edited Mar 6, 2009 at 3:29 AM by jbogard, version 1

Comments

jtu100 Oct 30, 2012 at 12:54 PM 
Why is the advantage of using ResolveUsing instead of just UseValue within a ForMember call?

shailendrasute Aug 16, 2012 at 6:36 PM 
Can i map two types to form a destination type? Basically I am looking at merging two types to form destination type. Please help.

paul07481 Jun 19, 2011 at 8:18 AM 
Is it possible to make this fluent or is there a better way to do the following?
For example if I have a set of dates stored in UTC in my domain model and I need to convert them to local time for my view models it would be nice to write one custom resolver to do the date transformation and then do this every time I have a date in the domain model:
Mapper.CreateMap<Order, OrderModel>()
.ForMember(dest => dest.OrderDate, opt => opt.MapFrom(m => m.OrderDate).ResolveUsing<TimeZoneResolver>())
At present I think I need a new custom resolver don't I?
Thanks for a brilliant time saver by the way.

adamtolley Apr 20, 2011 at 7:17 PM 
Mapper.CreateMap<Source, Destination>().ForMember(dest => dest.Total, opt => opt.MapFrom(src => src.Value1 + src.Value2));
works just as well for the first example; Is there a reason to use Custom Value Resolution instead (other than as a way to specify something as a method rather than in a lambda)?

jordanhammond Nov 17, 2010 at 9:06 AM 
How would I configure my mappings to handle abstract classes.
Say I have abstract Class1 with a list of properties, and then Class2 & Class3 that implement the abstract Class1. Do I need to provide complete mappings for Class2 & Class3 for the properties that are defined in Class1? Or is it possible to map Class1 and have Class2 & Class3 inherit those mappings?

sbabai Sep 9, 2010 at 11:46 AM 
nice feature for reporting.