Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Unexpected Mapping Happens in AutoMapper?

I have a project using AutoMapper 3.1.1, I was able to isolate the issue I am running into.

Here are my test classes:

class BaseClass
{
    public string PropertyA { get; set; }
}

class DerivedClass: BaseClass
{
    public string PropertyB { get; set; }
}

class ContainerClass
{
    public DerivedClass ComplexProperty { get; set; }
    public string PropertyC { get; set; }
}

class SourceClass
{
    public string PropertyA { get; set; }
    public string PropertyB { get; set; }
    public string PropertyC { get; set; }
}

Here are my mapping rules:

Mapper.CreateMap<SourceClass, ContainerClass>()
    .ForMember(d => d.ComplexProperty, o => o.MapFrom(s => Mapper.Map<DerivedClass>(s)))
    .AfterMap((s, d) => System.Diagnostics.Debug.WriteLine("SourceClass-> ContainerClass mapped"));

Mapper.CreateMap<SourceClass, DerivedClass>()
    .AfterMap((s, d) => System.Diagnostics.Debug.WriteLine("SourceClass -> DerivedClass mapped"));

Mapper.CreateMap<BaseClass, DerivedClass>()
    .AfterMap((s, d) => System.Diagnostics.Debug.WriteLine("BaseClass -> DerivedClass mapped"));

Here is my code:

var source = new SourceClass {
    PropertyA = "ValueA",
    PropertyB = "ValueB",
    PropertyC = "ValueC",
};

var destination = Mapper.Map<ContainerClass>(source);

Console.WriteLine("PropertyA: " + destination?.ComplexProperty?.PropertyA);
Console.WriteLine("PropertyB: " + destination?.ComplexProperty?.PropertyB);
Console.WriteLine("PropertyC: " + destination?.PropertyC);

The output is:

PropertyA: ValueA
PropertyB:
PropertyC: ValueC

I expected PropertyB to have value of "ValueB", but it has value null instead. It happens, because mapper from BaseClass to DerivedClass executes for some reason. My debug output is the following:

SourceClass -> DerivedClass mapped
BaseClass -> DerivedClass mapped
SourceClass -> ContainerClass mapped

Why AutoMapper executes BaseClass -> DerivedClass mapping?


UPDATE: Thank to Marius I now know that mapping from BaseClass to DerivedClass is invalid. I can not remove this mapping rule as he suggest, because I need it for my application. As exception suggests I added Ignore for the PropertyB:

Mapper.CreateMap<BaseClass, DerivedClass>()
    .ForMember(d => d.PropertyB, o => o.Ignore())
    .AfterMap((s, d) => System.Diagnostics.Debug.WriteLine("BaseClass -> DerivedClass mapped"));

Now Mapper.AssertConfigurationIsValid(); does not throw exception anymore. But the original question still stands. Why AutoMapper executes BaseClass -> DerivedClass mapping?

like image 597
Ivan Pankov Avatar asked Nov 08 '22 15:11

Ivan Pankov


1 Answers

When debugging AutoMapper issues I recommend to validate the configuration by calling Mapper.AssertConfigurationIsValid(); I added it to your code and I got the following exception message:

Error Message: AutoMapper.AutoMapperConfigurationException : Unmapped members were found. Review the types and members below. Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type

==================================

BaseClass -> DerivedClass (Destination member list) src.BaseClass -> src.DerivedClass (Destination member list)

PropertyB

You can solve the issue by removing the mapping for BaseClass -> DerivedClass. Then also the call to Mapper.AssertConfigurationIsValid(); does not throw anymore.

like image 119
Marius Avatar answered Nov 14 '22 23:11

Marius