AutoMapper 4.2.1 Abstract Mapping Issue

Created on 24 May 2016  Â·  10Comments  Â·  Source: AutoMapper/AutoMapper

I’m currently having an issue with mapping a list of abstract types using AutoMapper.

I have an abstract object called BaseDomain, which is derived by DomainA and DomainB. I also have the same structure for my data contracts with the suffix Dto at the end.
I’m trying to use AutoMapper to map a list of BaseDomains containing both DomainA and DomainB objects to the relevant data contracts. Previously I have achieved this by using the Include method.

However, due to an important architecture change mappings that previously used the Include method have now stopped working and throw the following error ‘System.InvalidOperationException: Instances of abstract classes cannot be created.’

I have tracked the issue down to a configuration issue. I have provided two examples below. Both scenarios are the same with the small exception of how AutoMapper is configured.

Scenario one configures AutoMapper configuration in the MappingConfiguration object delegate. This maps a list of BaseDomain objects correctly without throwing an exception.

Scenario two configures AutoMapper configuration after the MappingConfiguration delegate has been executed. This doesn’t map a list of BaseDomain objects and will throw the exception mentioned above however, this example will map a list of DomainA objects.

I have provided the code for both scenarios below. Which were written in LINQPad4. The example is using AutoMapper 4.2.1. It would be really good if we could get scenario 2 to work correctly as this would then adhere to our architecture.

Scenario one: Works for abstract and non-abstract types

void Main()
{

    IMapperConfiguration _mappingConfig = new MapperConfiguration(Configure);    
    IMapper _objectMapper = ((MapperConfiguration)_mappingConfig).CreateMapper();

    var baseDomainObjects = new List<BaseDomain>
    {
        new DomainA { Id = 1, Text = "Domain A", ExtraPropertyA = "A" },
        new DomainB { Id = 2, Text = "Domain B", ExtraPropertyB = "B" }
    };

    var domainObjectDtos = _objectMapper.Map<List<BaseDomainDto>>(baseDomainObjects);

    domainObjectDtos.Dump();    
}

void Configure(IMapperConfiguration mapperConfiguration)
{       
   mapperConfiguration.CreateMap<BaseDomain, BaseDomainDto>()
                .Include<DomainA, DomainADto>()
                .Include<DomainB, DomainBDto>();

    mapperConfiguration.CreateMap<DomainA, DomainADto>();
    mapperConfiguration.CreateMap<DomainB, DomainBDto>();
}

public abstract class BaseDomain
{
    public int Id {get;set;}
    public string Text {get;set;}
}

public class DomainA : BaseDomain
{
    public string ExtraPropertyA {get;set;}
}

public class DomainB : BaseDomain
{
    public string ExtraPropertyB {get;set;}
}

public abstract class BaseDomainDto
{
    public int Id {get;set;}
    public string Text {get;set;}
}

public class DomainADto : BaseDomainDto
{
    public string ExtraPropertyA {get;set;}
}

public class DomainBDto : BaseDomainDto
{
    public string ExtraPropertyB {get;set;}
}

Scenario Two:- Doesn't work for abstract types however, works for non-abstract types

void Main()
{

    IMapperConfiguration _mappingConfig = new MapperConfiguration(Configure);

    _mappingConfig.CreateMap<BaseDomain, BaseDomainDto>()
                .Include<DomainA, DomainADto>()
                .Include<DomainB, DomainBDto>();

            _mappingConfig.CreateMap<DomainA, DomainADto>();
            _mappingConfig.CreateMap<DomainB, DomainBDto>();


    IMapper _objectMapper = ((MapperConfiguration)_mappingConfig).CreateMapper();

    var baseDomainObjects = new List<BaseDomain>
    {
        new DomainA { Id = 1, Text = "Domain A", ExtraPropertyA = "A" },
        new DomainB { Id = 2, Text = "Domain B", ExtraPropertyB = "B" }
    };

    var domainAObjects = new List<DomainA>
    {
        new DomainA { Id = 1, Text = "A", ExtraPropertyA = "A" },
        new DomainA { Id = 2, Text = "B", ExtraPropertyA = "B" },
        new DomainA { Id = 3, Text = "C", ExtraPropertyA = "C" },
    };


    var domainObjectDtos = _objectMapper.Map<List<BaseDomainDto>>(baseDomainObjects);
    //var domainAObjectDtos = _objectMapper.Map<List<DomainADto>>(domainAObjects);

    domainObjectDtos.Dump();    
    //domainAObjectDtos.Dump();
}

void Configure(IMapperConfiguration mapperConfiguration)
   {       
   }

public abstract class BaseDomain
{
    public int Id {get;set;}
    public string Text {get;set;}
}

public class DomainA : BaseDomain
{
    public string ExtraPropertyA {get;set;}
}

public class DomainB : BaseDomain
{
    public string ExtraPropertyB {get;set;}
}

public abstract class BaseDomainDto
{
    public int Id {get;set;}
    public string Text {get;set;}
}

public class DomainADto : BaseDomainDto
{
    public string ExtraPropertyA {get;set;}
}

public class DomainBDto : BaseDomainDto
{
    public string ExtraPropertyB {get;set;}
}
Feature

Most helpful comment

Just to illustrate what I'm shooting for:

// Do it all in one go
public MapperConfiguration(Action<IMapperConfiguration> configure) {}

// You modify MapperConfigurationExpression with CreateMap, etc. When you're done, give it to the MapperConfiguration for it to be "done". You'd use this one, and pass a MapperConfigurationExpression around.
public MapperConfiguration(MapperConfigurationExpression expression) {}

All 10 comments

That's because the first example is the right way to initialize AutoMapper :) The second is just undefined.

I have the same issue, why does registering the abstract types in the Configure() method work but not when you configure the mappings using the variable returned from the "new MapperConfiguration(Configure);" creation method. Configure uses the same type as its input as the return type of MapperConfiguration().

e.g.
IMapperConfiguration _mappingConfig = new MapperConfiguration(Configure);
void Configure(IMapperConfiguration mapperConfiguration)

They both use IMapperConfiguration?

The fluent interface allows the syntax but depending on where you use it depends on the result, doesn't seem correct.

Its only when IMapper _objectMapper = ((MapperConfiguration)_mappingConfig).CreateMapper(); is called that the _mappingConfig variable is used to build the mappings.

Hmmm, you're right, those two should be separated. I'll make sure they do before the 5.0 release.

For now, don't do that casting stuff. Initialize everything from the constructor.

Just to be clear. I think that @jbogard is saying is that the second example won't compile anymore.

Thanks for your replies. However I don't understand the benefits of having to register your mappings in the construction of the IMapperConfiguration. This just means that I have to break boundaries in my application by having to reference IMapperConfiguration in the delegate methods that register the mappings.

That's what I'll be doing - breaking out the "configuration gatherer" from the "configuration holder". It's important that ALL configuration gathering is done before I apply them to the configuration holder. I have to apply configuration _in the correct order_, and this can only be easily done if it's a two step process, gathering configuration and applying configuration.

Just to illustrate what I'm shooting for:

// Do it all in one go
public MapperConfiguration(Action<IMapperConfiguration> configure) {}

// You modify MapperConfigurationExpression with CreateMap, etc. When you're done, give it to the MapperConfiguration for it to be "done". You'd use this one, and pass a MapperConfigurationExpression around.
public MapperConfiguration(MapperConfigurationExpression expression) {}

This makes sense now, I think the comment from @lbargaoanu confused matters a little. Thanks your reply. Look forward to seeing this feature in the future.

Boom #1304

This thread 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