A project I'm working on (still in .NET Framework, in case that matters) uses AutoMapper for two separate projects that use the same Database and share a LOT of the same view model classes from a Common class library project, e.g.:
// in Project 1
Mapper.Initialize(cfg =>
{
cfg.CreateMap<A, AModel>()
.ForMember(dest => dest.Prop1, opt => opt.MapFrom(src => src.PropertyName))
.ForMember(dest => dest.Prop2, opt => opt.MapFrom(src => src.OtherPropertyName));
cfg.CreateMap<B2, BModel>()
.ForMember(dest => dest.Prop1, opt => opt.MapFrom(src => src.PropertyName))
.ForMember(dest => dest.Prop2, opt => opt.MapFrom(src => src.OtherPropertyName))
.ForMember(dest => dest.Prop3, opt => opt.MapFrom(src => src.OtherOTHERPropertyName));
}
// in Project 2
Mapper.Initialize(cfg =>
{
cfg.CreateMap<A, AModel>()
.ForMember(dest => dest.Prop1, opt => opt.MapFrom(src => src.PropertyName))
.ForMember(dest => dest.Prop2, opt => opt.MapFrom(src => src.OtherPropertyName));
cfg.CreateMap<B2, BModel>()
.ForMember(dest => dest.Prop1, opt => opt.MapFrom(src => src.PropertyName))
.ForMember(dest => dest.Prop2, opt => opt.MapFrom(src => src.OtherPropertyName))
.ForMember(dest => dest.Prop3, opt => opt.Ignore());
}
I'd like to move all of the duplicate mappings (which is most of them) into a profile or something in the Common project:
public class CommonAutoMapperProfile : Profile
{
public CommonAutoMapperProfile()
{
CreateMap<A, AModel>()
.ForMember(dest => dest.Prop1, opt => opt.MapFrom(src => src.PropertyName))
.ForMember(dest => dest.Prop2, opt => opt.MapFrom(src => src.OtherPropertyName));
CreateMap<B, BModel>()
.ForMember(dest => dest.Prop1, opt => opt.MapFrom(src => src.PropertyName))
.ForMember(dest => dest.Prop2, opt => opt.MapFrom(src => src.OtherPropertyName));
}
}
This is no problem for the COMPLETELY identical mappings like A->AModel, but I'm struggling with ones like B->BModel that differ by even ONE ForMember call (Prop3 in this case), which Project 1 sets and Project 2 ignores. It DOES apply that rule, but it seems that when the second CreateMap is called, ALL mappings set by CommonAutoMapperProfile get thrown out entirely:
// in project 1
Mapper.Initialize(cfg =>
{
cfg.AddProfile<CommonAutoMapperProfile>();
cfg.CreateMap<B, BModel>()
.ForMember(dest => dest.Prop3, opt => opt.MapFrom(src => src.OtherOTHERPropertyName));
// BModel.Prop1 and BModel.Prop2 are still null; BModel.Prop3 is the only one being set
}
I'd LIKE it to "merge" the mappings together, i.e. retain the property mappings defined in CommonAutoMapperProfile and add the project-specific ones on top. Is that something AutoMapper just... CAN'T do?
I've also attempted creating ANOTHER Profile class that is specific to each project, with unfortunately the same results, whether I'm adding it with another cfg.AddProfile call:
public class Project1AutoMapperProfile : Profile
{
public Project1AutoMapperProfile()
{
CreateMap<B, BModel>()
.ForMember(dest => dest.Prop3, opt => opt.MapFrom(src => src.OtherOTHERPropertyName));
}
}
// elsewhere in Project 1...
Mapper.Initialize(cfg =>
{
cfg.AddProfile<CommonAutoMapperProfile>();
cfg.AddProfile<Project1AutoMapperProfile>();
}
or having it inherit from CommonAutoMapperProfile:
public class Project1AutoMapperProfile : CommonAutoMapperProfile
{
public Project1AutoMapperProfile()
{
CreateMap<B, BModel>()
.ForMember(dest => dest.Prop3, opt => opt.MapFrom(src => src.OtherOTHERPropertyName));
}
}
// elsewhere in Project 1...
Mapper.Initialize(cfg =>
{
cfg.AddProfile<Project1AutoMapperProfile>();
}
Both cases had the exact same results as the first case: ONLY the mappings in Project1AutoMapperProfile were being applied
As mentioned in the comments, what you have is not an ideal design. But I understand that sometimes we have to work with the cards we're dealt (e.g. you have no access to modify the models).
As the name implies, calling
CreateMapmultiple times for the same mapping will just keep creating a new one. If you want to build up from an existing one, you have to append/modify. There's no built-in facility to get and existing map and modify it, but we can be a little sneaky and implement it ourselves.NOTE: I still do not recommend doing this. If you can break up your models, do that and use the recommended model inheritance.
That said, the code below works. For the current version of AutoMapper. For this specific case. Make sure you have good test coverage, in case it breaks in the future, or for some of your more complex models.
We then create a derived profile which will modify the mapping in the Common one.