'automapper map interface to interface or object

How to map objects inherited from one interface to objects inherited from another interface.

I have such code structure

public interface IDataTranslatable
{
    List<DataTranslation> SpanishDataTranslations {get;set;}
}

public interface IDataTranslatableDto
{
    List<DataTranslationDto> DataTranslations { get; set; }
}

objects DataTranslation and DataTranslationDto have the same properties. I have many objects inherited from IDataTranslatable and IDataTranslatableDto interfaces. For example

public class Category : IDataTranslatable
{
    public string Name { get; set; }
    public ICollection<DataTranslation> SpanishDataTranslations { get; set; } = new List<DataTranslation>();
}

public class CategoryDto : IDataTranslatableDto
{
    public string Name { get; set; }
    public List<DataTranslationDto> DataTranslations { get; set; } = new List<DataTranslationDto>();
}

The best implementation for me would be something like that

config.CreateMap<IDataTranslatable, IDataTranslatableDto>()
.ForMember(dest => dest.DataTranslations, opts => opts.MapFrom(src => src.SpanishDataTranslations));

By this I mean that any object inherited from IDataTranslatable has to be mapped to object inherited IDataTranslatableDto to corresponding fields.

But this won't work, So I've tried to map like that

config.CreateMap<IDataTranslatable, CategoryDto>()
.ForMember(dest => dest.DataTranslations, opts => opts.MapFrom(src => src.SpanishDataTranslations));

Current using

public class AutoMapperConfiguration : IAutoMapperConfiguration
{
    public void Configure(IMapperConfigurationExpression config)
    {
        IDataTranslatableMappings(config);
    }

    private void IDataTranslatableMappings(IMapperConfigurationExpression config)
    {
        var mapCategory = config.CreateMap<Category, CategoryDto>().ForMember(dest => dest.DataTranslations, opts => opts.MapFrom(src => src.SpanishDataTranslations));
    }
}

This variant doesn't work as well. I've tried to explain my idea, how would be better to do it?



Solution 1:[1]

You can configure it the following way:

Mapper.Initialize(config =>
{
    config.CreateMap<IDataTranslatable, IDataTranslatableDto>()
                .ForMember(x => x.DataTranslations, y => y.MapFrom(src => src.SpanishDataTranslations));
                
    config.CreateMap<Category, CategoryDto>()
                .IncludeBase<IDataTranslatable, IDataTranslatableDto>();                    

    config.CreateMap<DataTranslation, DataTranslationDto>();
});

And the usage of it:

var translation = new DataTranslation()
{
    Test = "Foo"
};

IDataTranslatable category = new Category()
{
     SpanishDataTranslations = new List<DataTranslation> { translation }
};

var result = Mapper.Map<IDataTranslatableDto>(category);

You will be forced to add every implementation of IDataTranslatable and IDataTranslatableDto to the mapping configuration.


Update

From version 8.0 and above, you can use IncludeDerived on your base type and therefore no longer need to explicitly declare all implementations of your interface.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1