Automapper: IncludeBase is ignored when ForAllOtherMembers are used

Created on 30 Oct 2020  路  9Comments  路  Source: AutoMapper/AutoMapper

IncludeBase and ForAllOtherMembers does not cooperate. When using ForAllOtherMembers the IncludeBase mappings are ignored.

Source/destination types

// Source types
    internal abstract class Base
    {
        public int Id { get; set; }

        public DateTimeOffset Created { get; set; }

        public DateTimeOffset Modified { get; set; }
    }

    internal class Person : Base
    {
        public string Name { get; set; }

        public string IgnoredProperty { get; set; }
    }

// Destination types
    public abstract class BaseDTO
    {
        public int Id { get; set; }

        public DateTimeOffset Created { get; set; }

        public DateTimeOffset Modified { get; set; }
    }

    public class PersonDTO : BaseDTO
    {
        public string Name { get; set; }

        public string IgnoredProperty { get; set; }
    }

Mapping configuration

var config = new MapperConfiguration(cfg =>
            {
                cfg.CreateMap<Base, BaseDTO>()
                   .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
                   .ForMember(dest => dest.Created, opt => opt.MapFrom(src => src.Created))
                   .ForMember(dest => dest.Modified, opt => opt.MapFrom(src => src.Modified));

                cfg.CreateMap<Person, PersonDTO>()
                   // Include base mappings
                   .IncludeBase<Base, BaseDTO>()
                   .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name))
                   // Ignore all other properties
                   .ForAllOtherMembers(opt => opt.Ignore()); // Removing this and it will work
            });

Version: 10.1.1

Expected behavior

The base mapping should be added with the IncludeBase even if ForAllOtherMembers is configured.

Actual behavior

The mappings provided with the IncludeBase should be mapped even when ForAllOtherMembers is configured.

Steps to reproduce

            var p = new Person
            {
                Id = 1,
                Created = DateTimeOffset.Now,
                Modified = DateTimeOffset.Now,
                Name = "A Test Name",
                IgnoredProperty = "This is the ignored property."
            };

            var result = mapper.Map<PersonDTO>(p);

            // This is mapped
            Assert.Equal(p.Name, result.Name);

            // Success because of ForAllOtherMembers option
            Assert.Null(result.IgnoredProperty); 

            // Everything below here fails, while it shouldn't since IncludeBase is used
            Assert.Equal(p.Created, result.Created);
            Assert.Equal(p.Modified, result.Modified);
            Assert.Equal(p.Id, result.Id);
Question

All 9 comments

Just use MemberList.None for that map. ForAllOtherMembers is tricky :)

@jbogard Here's another feature waiting for its earthly demise. Or smth.

Sigh. Probably so, I don't even know how it works or what it does 馃槅

It ignores everything not explicitly configured. It works by considering things at config time, which of course won't work for included maps. But stepping back, what does this do besides validation? I guess it ignores members that would otherwise match. Kind of anti AutoMapper. I'm not sure we really want that.

Ohhhh yes this is "ExplicitMapper", yeah what's the point of this mapping? Only map things I explicitly configure, and ignore the rest?

Yeah but it's a little bit different than validation, this will ignore auto-mapped members too.

I think it should go, tbqh

Another option is a simple extension method:

    public static IMappingExpression<TSource, TDestination> Ignore<TSource, TDestination>(
        this IMappingExpression<TSource, TDestination> mapping,
        params Expression<Func<TDestination, object>>[] members)
    {
        foreach (var member in members)
        {
            mapping.ForMember(member, o => o.Ignore());
        }
        return mapping;
    }

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings