I think this is an AutoMapper bug but the issue template they have in GitHub states to post something to SO first.
I want to be able to apply an IValueConverter
without worrying about null exceptions.
As an example, I'm using a IValueConverter
to apply some logic in multiple mappings:
public class ExampleConverter : IValueConverter<string, string>
{
public string Convert(string sourceMember, ResolutionContext context)
{
if (string.IsNullOrEmpty(sourceMember))
{
return string.Empty;
}
return sourceMember.ToUpper();
}
}
If I have the following types I'm mapping to and from:
public class ExampleSource
{
public ExampleNestedSource1 A { get; set; }
}
public class ExampleNestedSource1
{
public ExampleNestedSource2 B { get; set; }
}
public class ExampleNestedSource2
{
public string Input { get; set; }
}
public class ExampleDestination
{
public string Output { get; set; }
}
I can apply the converter like so:
public class ExampleProfile : Profile
{
public ExampleProfile()
{
this.CreateMap<ExampleSource, ExampleDestination>(MemberList.None)
.ForMember(dst => dst.Output, opt => opt.ConvertUsing(new ExampleConverter(), src => src.A.B.Input));
}
}
Using the converter like this however, throws an exception when A or B are null:
mapper.Map<ExampleDestination>(new ExampleSource // Throws null reference
{
A = new ExampleNestedSource1(),
});
mapper.Map<ExampleDestination>(new ExampleSource()); // Throws null reference
Because opt.ConvertUsing(new ExampleConverter(), src => src.A.B.Input)
takes in an expression I can't use null propagating operators like src?.A?.B?.Input
.
If I remove the converter and use MapFrom
, the problem goes away:
public class ExampleProfile : Profile
{
public ExampleProfile()
{
this.CreateMap<ExampleSource, ExampleDestination>(MemberList.None)
.ForMember(dst => dst.Output, opt => opt.MapFrom(src => src.A.B.Input));
}
}
But MapFrom
doesn't support IValueConverter
it only supports IMemberValueResolver
which is less reusable.
Is there a better way to handle this scenario?
If not, I'm thinking AutoMapper should either:
- Add support for
IValueConverter
in theMapFrom
method. ConvertUsing
should not invoke the given converter when the expression doesn't resolve to a property and not throw.ConvertUsing
should invoke the given converter with null when the expression doesn't resolve to a property (in the same way thatMapFrom
) and not throw.