question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

AutoMapper 4.2.1 Abstract Mapping Issue

See original GitHub issue

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;}
}

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:10 (6 by maintainers)

github_iconTop GitHub Comments

2reactions
jbogardcommented, May 24, 2016

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) {}
1reaction
jbogardcommented, May 24, 2016

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.

Read more comments on GitHub >

github_iconTop Results From Across the Web

c# - Automapper 4.2.1 - Flat model to a abstract base class ...
I am having trouble mapping from a Flat model to a abstract base class (TPT structure). using version 4.2.1 Source Model:
Read more >
AutoMapper.xml 4.2.1
Creates a mapping configuration from the source type to the destination type. Specify the member list to validate against during configuration validation. </ ......
Read more >
AutoMapper 4.2.1
First step would be to create a class inheriting from AutoMapper.Profile class. Then, override the Configure function to create mapping between ...
Read more >
AutoMapper.Mapper.CreateMap<TSource,TDestination> ...
Use CreateMapper to create a mapper instance. 4384 views ... I'm trying to upgrade with 4.2.1 i'm facing a problem, like below.
Read more >
Object To Object Mapping | Documentation Center | ABP.IO
ABP provides abstractions for object to object mapping and has an integration package to use AutoMapper as the object mapper.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found