jcnewman83
jcnewman83

Reputation: 199

Automapper custom value resolver reuse for multiple types

I have a project which I am trying to use AutoMapper to map from multiple classes in each of these classes there are properties where I would like to use some custom logic to parse the source value to the destination. I have tried to use custom resolver methods as documented on the AutoMapper docs.

Here is my code:

public class CustomDateTextHandler : IValueResolver<object, object, string>
{
    public string Resolve(object source, object destination, string destMember, ResolutionContext context)
    {
        string txt = source.ToString();
        txt.Replace("AM/PM", "tt");
        txt.Replace("HH:MM", "hh:mm");
        if (txt.Contains("format"))
        {
            txt.Replace("mmm", "MMM");
        }
        return txt;
    }
}

public class SMapping : Profile
{
    public SMapping()
    {
        CreateMap<SourceForm, s_form>()
            .ForMember(dest => dest.id, opt => opt.Ignore())
            .ForMember(dest => dest.cell_text, opt => opt.MapFrom<CustomDateTextHandler>())
            .ForMember(dest => dest.fn_def, opt => opt.MapFrom<CustomCodeTextResolver>());
    }

What I am trying to get is the cell_text value processed with my replace logic in the resolver method but the issue I am facing is that what is being passed to the resolver is the entire SMapping instance, I would like to be able to reuse the resolver code across different classes where the property names will be different, however looking at what it going on at the moment I could not really use the resolver code across my different classes.

Can someone help me?

Thank you in advance.

Upvotes: 4

Views: 4434

Answers (1)

quetzalcoatl
quetzalcoatl

Reputation: 33526

Use IMemberValueResolver instead of IValueResolver.
Compared to IValueResolver, its Resolve function gets one more parameter: value.
Registering mapping with IMemberValueResolver requires you to pass 1 extra parameter - not the 'value' directly, but a lambda that will produce a 'value' from given source object.

public class CustomDateTextHandler :
    IMemberValueResolver< // note: different interface
        object, object,
        string, string   // note: 1 more parameter
    >
{
    public string Resolve(
        object source, object destination,
        string sourceValue, string destMember, // note: 1 more parameter
        ResolutionContext context
    )
    {
        // here, see the difference:
        // source - source object, whole
        // sourceMember - value produced by extra lambda passed in mapping
    }
}

public class SMapping : Profile
{
    public SMapping()
    {
        CreateMap<SourceForm, s_form>()
            ...
            .ForMember(
                dest => dest.cell_text,
                opt => opt.MapFrom<CustomDateTextHandler, string>(source => source.PROPERTY11)) // note: this produces that sourceValue
            
            .ForMember(
                dest => dest.fn_def,
                opt => opt.MapFrom<CustomCodeTextResolver, string>(source => source.PROPERTY22)); // note: this produces that sourceValue
            
    }

Upvotes: 9

Related Questions