AutoMapper 4.2.1 Abstract Mapping Issue
See original GitHub issueI’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 BaseDomain
s 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:
- Created 7 years ago
- Comments:10 (6 by maintainers)
Top GitHub Comments
Just to illustrate what I’m shooting for:
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.