Objects can be passed to the resolver with the Items
Dictionary option. The standard API to do this is pretty verbose (as seen in the accepted answer) but can be simplified nicely using a few extension methods:
/// <summary>
/// Map using a resolve function that is passed the Items dictionary from mapping context
/// </summary>
public static void ResolveWithContext<TSource, TDest, TMember, TResult>(
this IMemberConfigurationExpression<TSource, TDest, TMember> memberOptions,
Func<TSource, IDictionary<string, object>, TDest, TMember, TResult> resolver
) {
memberOptions.ResolveUsing((src, dst, member, context) => resolver.Invoke(src, context.Items, dst, member));
}
public static TDest MapWithContext<TSource, TDest>(this IMapper mapper, TSource source, IDictionary<string, object> context, Action<IMappingOperationOptions<TSource, TDest>> optAction = null) {
return mapper.Map<TSource, TDest>(source, opts => {
foreach(var kv in context) opts.Items.Add(kv);
optAction?.Invoke(opts);
});
}
Which can be used like this:
// Define mapping configuration
Mapper.CreateMap<Comment, ImageComment>()
.ForMember(
d => d.ImageId,
opt => opt.ResolveWithContext(src, items, dst, member) => items["ImageId"])
);
// Execute mapping
var context = new Dictionary<string, object> { { "ImageId", ImageId } };
return mapper.MapWithContext<TSource, TDest>(source, context);
If you have an object that you commonly need to pass to mapper resolvers (for example, the current user), you can go one step further and define more specialized extensions:
public static readonly string USER_CONTEXT_KEY = "USER";
/// <summary>
/// Map using a resolve function that is passed a user from the
/// Items dictionary in the mapping context
/// </summary>
public static void ResolveWithUser<TSource, TDest, TMember, TResult>(
this IMemberConfigurationExpression<TSource, TDest, TMember> memberOptions,
Func<TSource, User, TResult> resolver
) {
memberOptions.ResolveWithContext((src, items, dst, member) =>
resolver.Invoke(src, items[USER_CONTEXT_KEY] as User));
}
/// <summary>
/// Execute a mapping from the source object to a new destination
/// object, with the provided user in the context.
/// </summary>
public static TDest MapForUser<TSource, TDest>(
this IMapper mapper,
TSource source,
User user,
Action<IMappingOperationOptions<TSource, TDest>> optAction = null
) {
var context = new Dictionary<string, object> { { USER_CONTEXT_KEY, user } };
return mapper.MapWithContext(source, context, optAction);
}
Which can be used like:
// Create mapping configuration
Mapper.CreateMap<Source, Dest>()
.ForMember(d => d.Foo, opt => opt.ResolveWithUser((src, user) src.Foo(user));
// Execute mapping
return mapper.MapWithUser(source, user);