1

I'm a AutoMapper newb. My mappings are not working as expected and I'm sure I'm doing somthing wrong but can't figure it out. Sorry if this question is confusing, but i'll do my best to be clear. Lets say we have three classes:

public class Person
{
    public ContactInfo1 Contact { get; set; }
}

public class ContactInfo1
{
    public string Name { get; set; }
}

public class ContactInfo2
{
    public string AnotherName { get; set; }
}

Now, I want to setup my mappings so that ContactInfo1 can map to and from ContactInfo2. And then I want to be able to map Person1 -> ContactInfo2 (which might look stange, but I need to do it anyway). I have tried the following mapping config:

var autoMapperConfig = new AutoMapper.MapperConfiguration(cfg =>
{
    cfg.CreateMap<ContactInfo1, ContactInfo2>()
        .ForMember(dest => dest.AnotherName, opt => opt.MapFrom(src => src.Name)).ReverseMap();
    cfg.CreateMap<ContactInfo2, Person>()
        .ForMember(dest => dest.Contact, opt => opt.MapFrom(src => src)).ReverseMap();
    });

var mapper = autoMapperConfig.CreateMapper();

For the test data:

var testPerson = new Person();
testPerson.Contact = new ContactInfo1() { Name = "Person1" };

I do the following:

var contactInfo2Test = mapper.Map<Person, ContactInfo2>(testPerson);

This does NOT give me any errors, but contactInfo2Test.AnotherName is empty. Please advise! Thanks.

Please note that I realize I could go:

cfg.CreateMap<Person, ContactInfo2>()
    .ForMember(dest => dest.AnotherName, opt => opt.MapFrom(src => src.Contact.Name));

Bu then I would have mapped Contact1->Contact2 all over again, and in a more complex scenario I really want to avoid that.

tmatuschek
  • 608
  • 4
  • 15
  • Try this `cfg.CreateMap() .ForMember(dest => dest.Contact.Name, opt => opt.MapFrom(src => src)).ReverseMap(); ` – Abdul Samad Mar 09 '18 at 12:16
  • Thanks Abdul, but I can't really see how that would work (I tried it anyway and I saying dest => dest.Contact.Name' must resolve to top-level member and not any child object's properties). – tmatuschek Mar 09 '18 at 12:24

1 Answers1

2

Here's one way of doing it:

var autoMapperConfig = new AutoMapper.MapperConfiguration(cfg =>
{
    cfg.CreateMap<ContactInfo1, ContactInfo2>()
        .ForMember(dest => dest.AnotherName, opt => opt.MapFrom(src => src.Name))
        .ReverseMap();
    cfg.CreateMap<Person, ContactInfo2>()
        .ConstructUsing((p, ctx) => ctx.Mapper.Map<ContactInfo2>(p.Contact));
});
asherber
  • 2,508
  • 1
  • 15
  • 12
  • Thanks asherber! It feels a bit "dirty/hacky" to use the mapper inside itself this way, but perhaps it is the way to go. Or do you know more ways around it? – tmatuschek Mar 12 '18 at 13:20
  • Actually, I think the resolution context exposes the mapper for exactly things like this. If you think about it, there are all kinds of times when Automapper implicitly uses knowledge it already has. For example, if you look at your initial code, you were relying on the fact that you had already told Automapper how to map `ContactInfo1` to `ContactInfo2` in order to map `Person` to `ContactInfo2`. My code just does this explicitly. – asherber Mar 12 '18 at 13:40
  • Yes, I think it is the fact that I need to be explicit is what makes me feel like I'm doing something backwards. But I'll try this and mark it as the answer if it works out like I expect. Once again, thanks for taking the time, really appreciate it! – tmatuschek Mar 13 '18 at 06:47