Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why would an AutoMapperExtension behave differently from a direct implementation?

Tags:

c#

automapper

I have defined the following mapping within RegisterMappings() of AutoMapperConfig:

AutoMapper.Mapper.CreateMap<Member, PhotoViewModel>()
            .ForMember(dest => dest.Show, opt => opt.MapFrom(src => src.ShowPhoto))
            .ForMember(dest => dest.Value, opt => opt.MapFrom(src => AutoMapper.Mapper.Map<PhotoValueViewModel>(src));
AutoMapper.Mapper.CreateMap<Member, PhotoValueViewModel>();

This mapping maps two properties of a PhotoViewModel. First it maps the Show property based off of src.ShowPhoto, and then it maps a PhotoValueViewModel into the Value property.

The mapping works! Unfortunately, I have many objects that require a similar mapping. So, I tried abstracting some of the implementation into an AutoMapperExtension method. The method looks like this:

public static IMappingExpression<TSource, TDestination> ApplyPropertyMapping<TSource, TDestination>
        (this IMappingExpression<TSource, TDestination> iMappingExpression, Expression<Func<TSource, bool?>> show, Expression<Func<TSource, object>> value)
        where TDestination : PropertyViewModel
    {
        iMappingExpression
            .ForMember(dest => dest.Show, opt => opt.MapFrom(show))
            .ForMember(dest => dest.Value, opt => opt.MapFrom(value));
        return iMappingExpression;
    }

I'd expect this extension method to allow me to define the original mapping as:

AutoMapper.Mapper.CreateMap<Member, PhotoViewModel>()
    .ApplyPropertyMapping(src => src.ShowPhoto, src => AutoMapper.Mapper.Map<PhotoValueViewModel>(src));

But it doesn't work! Now calls to Mapper.Map<Member, PhotoViewModel>(MemberObject, PhotoViewModelObject) set the PhotoViewModelObject.Value property to null.

What is causing the difference?

The definitions of some of these objects are:

public class Member
{
    /**Irrelevant Properties Not Shown**/
    public Guid? PhotoID { get; set; }
    public string PhotoFileName { get; set; }
    public bool? ShowPhoto { get; set; }
}

public class PropertyViewModel
{
    public object Value { get; set; }
    public bool? Show { get; set; }
}

public class PhotoViewModel : PropertyViewModel
{
    public PhotoValueViewModel Value { get; set; }
}

public class PhotoValueViewModel
{
    public Guid? PhotoID { get; set; }
    public string PhotoFileName { get; set; }
    public string PhotoUrl {get {return Utils.GeneratePhotoUrl(PhotoID); } }
}
like image 302
asemahle Avatar asked Jan 25 '26 13:01

asemahle


1 Answers

The PhotoViewModel class contains two properties with the name Value, one of them is defined in PropertyViewModel and is of type object. And the other one is defined in PhotoViewModel and is of type PhotoValueViewModel (this is basically hiding the other property, you should be getting a warning about this from Visual Studio).

Inside your extension method you are referencing PropertyViewModel.Value which is of type object

This is because the TDestination type is declared in this method to be assignable from PropertyViewModel (via where TDestination : PropertyViewModel).

Your extension method is working correctly, it is changing the value of that property (PropertyViewModel.Value).

Your original mapping (without the extension method) is mapping the value to PhotoViewModel.Value which is of type PhotoValueViewModel.

You can use Visual Studio debugger to watch both PropertyViewModel.Value and PhotoViewModel.Value in both cases (with or without the extension method).

like image 69
Yacoub Massad Avatar answered Jan 27 '26 02:01

Yacoub Massad



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!