views:

451

answers:

1

Hello,

I have an AutoMapper issue that has been driving me crazy for way too long now. A similar question was also posted on the AutoMapper user site but has not gotten much love.

The summary is that I have a container class that holds a Dictionary of components. The components are a derived object of a common base class. I also have a parallel structure that I am using as DTO objects to which I want to map.

The error that gets generated seems to say that the mapper cannot map between two of the classes that I have included in the CreateMap calls. I think the error has to do with the fact that I have a Dictionary of objects that are not part of the container‘s hierarchy.

I apologize in advance for the length of the code below. My simple test cases work. Needless to say, it’s only the more complex case that is failing.

Here are the classes:

#region Dto objects

public class ComponentContainerDTO
{
    public Dictionary<string, ComponentDTO> Components { get; set; }

    public ComponentContainerDTO()
    {
        this.Components = new Dictionary<string, ComponentDTO>();
    }
}

public class EntityDTO : ComponentContainerDTO
{
    public int Id { get; set; }

}

public class ComponentDTO
{
    public EntityDTO Owner { get; set; }
    public int Id { get; set; }
    public string Name { get; set; }
    public string ComponentType { get; set; }
}

public class HealthDTO : ComponentDTO
{
    public decimal CurrentHealth { get; set; }

}

public class PhysicalLocationDTO : ComponentDTO
{
    public Point2D Location { get; set; }
}
#endregion


#region Domain objects

public class ComponentContainer
{
    public Dictionary<string, Component> Components { get; set; }

    public ComponentContainer()
    {
        this.Components = new Dictionary<string, Component>();
    }
}

public class Entity : ComponentContainer
{
    public int Id { get; set; }

}

public class Component
{
    public Entity Owner { get; set; }
    public int Id { get; set; }
    public string Name { get; set; }
    public string ComponentType { get; set; }

}

public class Health : Component
{
    public decimal CurrentHealth { get; set; }
}

public struct Point2D
{
    public decimal X;
    public decimal Y;

    public Point2D(decimal x, decimal y)
    {
        X = x;
        Y = y;
    }
}

public class PhysicalLocation : Component
{
    public Point2D Location { get; set; }
}
#endregion

The code:

var entity = new Entity() { Id = 1 };
var healthComponent = new Health() { CurrentHealth = 100, Owner = entity, Name = "Health", Id = 2 };
entity.Components.Add("1", healthComponent);
var locationComponent = new PhysicalLocation() { Location = new Point2D() { X = 1, Y = 2 }, Owner = entity, Name = "PhysicalLocation", Id = 3 };
entity.Components.Add("2", locationComponent);

Mapper.CreateMap<ComponentContainer, ComponentContainerDTO>()
    .Include<Entity, EntityDTO>();

Mapper.CreateMap<Entity, EntityDTO>();

Mapper.CreateMap<Component, ComponentDTO>()
    .Include<Health, HealthDTO>()
    .Include<PhysicalLocation, PhysicalLocationDTO>();

Mapper.CreateMap<Component, ComponentDTO>();
Mapper.CreateMap<Health, HealthDTO>();
Mapper.CreateMap<PhysicalLocation, PhysicalLocationDTO>();

Mapper.AssertConfigurationIsValid();

var targetEntity = Mapper.Map<Entity, EntityDTO>(entity);

The error when I call Map() (abbreviated stack crawls):

AutoMapper.AutoMapperMappingException was unhandled
  Message=Trying to map MapperTest1.Entity to MapperTest1.EntityDTO.
Using mapping configuration for MapperTest1.Entity to MapperTest1.EntityDTO
Exception of type 'AutoMapper.AutoMapperMappingException' was thrown.
  Source=AutoMapper
  StackTrace:
       at AutoMapper.MappingEngine.AutoMapper.IMappingEngineRunner.Map(ResolutionContext context)
.
.
.

  InnerException: AutoMapper.AutoMapperMappingException
       Message=Trying to map System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[MapperTest1.Component, ElasticTest1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] to System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[MapperTest1.ComponentDTO, ElasticTest1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].
Using mapping configuration for MapperTest1.Entity to MapperTest1.EntityDTO
Destination property: Components
Exception of type 'AutoMapper.AutoMapperMappingException' was thrown.
       Source=AutoMapper
       StackTrace:
            at AutoMapper.Mappers.TypeMapObjectMapperRegistry.PropertyMapMappingStrategy.MapPropertyValue(ResolutionContext context, IMappingEngineRunner mapper, Object mappedObject, PropertyMap propertyMap)
.
.

       InnerException: AutoMapper.AutoMapperMappingException
            Message=Trying to map System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[MapperTest1.Component, ElasticTest1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] to System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[MapperTest1.ComponentDTO, ElasticTest1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].
Using mapping configuration for MapperTest1.Entity to MapperTest1.EntityDTO
Destination property: Components
Exception of type 'AutoMapper.AutoMapperMappingException' was thrown.
            Source=AutoMapper
            StackTrace:
                 at AutoMapper.MappingEngine.AutoMapper.IMappingEngineRunner.Map(ResolutionContext context)
                 .
            InnerException: AutoMapper.AutoMapperMappingException
                 Message=Trying to map MapperTest1.Component to MapperTest1.ComponentDTO.
Using mapping configuration for MapperTest1.Health to MapperTest1.HealthDTO
Destination property: Components
Exception of type 'AutoMapper.AutoMapperMappingException' was thrown.
                 Source=AutoMapper
                 StackTrace:
                      at AutoMapper.MappingEngine.AutoMapper.IMappingEngineRunner.Map(ResolutionContext context)
                      .
.

                 InnerException: AutoMapper.AutoMapperMappingException
                      Message=Trying to map System.Decimal to System.Decimal.
Using mapping configuration for MapperTest1.Health to MapperTest1.HealthDTO
Destination property: CurrentHealth
Exception of type 'AutoMapper.AutoMapperMappingException' was thrown.
                      Source=AutoMapper
                      StackTrace:
                           at AutoMapper.Mappers.TypeMapObjectMapperRegistry.PropertyMapMappingStrategy.MapPropertyValue(ResolutionContext context, IMappingEngineRunner mapper, Object mappedObject, PropertyMap propertyMap)

.
.
                      InnerException: System.InvalidCastException
                           Message=Unable to cast object of type 'MapperTest1.ComponentDTO' to type 'MapperTest1.HealthDTO'.
                           Source=Anonymously Hosted DynamicMethods Assembly
                           StackTrace:
                                at SetCurrentHealth(Object , Object )
.
.

Thank you in advance.

Rick

+2  A: 

This turned out to be a bug which has been fixed in version 1.1.0.184.

Thank you Jimmy for fixing it.

Rick

rboarman