'Automapper. How to map custom type property of inner class (source) to string and string array?

I want to map source inner classes to string and in other case string array but in both cases they are mapped to null. I want MapNoteFromInnerSourceEntity1 to hold a value of InnerSourceEntity1 Id property and MapValueFromInnerSourceEntity2 to hold values of InnerSourceEntity2 value properties. So far automapper is quite difficult for me to understand.

Code:

    internal class Program
{
    public class InnerSourceEntity1
    {
        public string Id { get; set; }
        public string Note { get; set; }
    }

    public class InnerSourceEntity2
    {
        public string Id { get; set; }
        public string Value { get; set; }
    }

    public class SourceEntity
    {
        public InnerSourceEntity1 A { get; set; }
        public IList<InnerSourceEntity2> B { get; set; }
    }

    public class DestinationEntity
    {
        public string MapNoteFromInnerSourceEntity1 { get; set; }
        public string[] MapValueFromInnerSourceEntity2 { get; set; }
    }

    static void Main()
    {
        var source = new SourceEntity
        {
            A = new InnerSourceEntity1 { Note = "Note", Id = "Id"},
            B = new List<InnerSourceEntity2> { new InnerSourceEntity2 { Id = "Id", Value = "Value" }, new InnerSourceEntity2 { Id = "Id", Value = "Value" } }
        };

        var config = new MapperConfiguration(cfg => {
            cfg.CreateMap<SourceEntity, DestinationEntity>();
            cfg.CreateMap<InnerSourceEntity1, string>().ConvertUsing(s => s.Note);
            cfg.CreateMap<IList<InnerSourceEntity2>, string[]>();
        });

        var mapper = new Mapper(config);
        DestinationEntity destination = mapper.Map<SourceEntity, DestinationEntity>(source);

        Console.ReadLine();
    }
}


Solution 1:[1]

Since the names of properties between source type SourceEntity and destination type DestinationEntity don't match, you'll have to explicitly indicate them, otherwise AutoMapper will not know how to fill the properties:

cfg.CreateMap<SourceEntity, DestinationEntity>()
    .ForMember(
        dst => dst.MapNoteFromInnerSourceEntity1,
        opts => opts.MapFrom(src => src.A))
    .ForMember(
        dst => dst.MapValueFromInnerSourceEntity2,
        opts => opts.MapFrom(src => src.B));

Also, don't map between concrete collection types:

cfg.CreateMap<IList<InnerSourceEntity2>, string[]>(); // <== Don't do that. 

Instead, see what the docs say about mapping collections:

(...) it’s not necessary to explicitly configure list types, only their member types. ~ AutoMapper Docs

So, you only need to specify map like this:

cfg.CreateMap<InnerSourceEntity2, string>();

And since we are mapping to string we also need to instruct the AutoMapper from where it can get the string value. So, we'll use ConvertUsing() again:

cfg.CreateMap<InnerSourceEntity2, string>().ConvertUsing(s => s.Value);

Final configuration:

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<SourceEntity, DestinationEntity>()
        .ForMember(
            dst => dst.MapNoteFromInnerSourceEntity1,
            opts => opts.MapFrom(src => src.A))
        .ForMember(
            dst => dst.MapValueFromInnerSourceEntity2,
            opts => opts.MapFrom(src => src.B));
    cfg.CreateMap<InnerSourceEntity1, string>().ConvertUsing(s => s.Note);
    cfg.CreateMap<InnerSourceEntity2, string>().ConvertUsing(s => s.Value);
});

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 Prolog