I have two classes, a ViewModel and a Dto, that are basically identical except that the Dto has a field 'readonly long? Phone;' while the ViewModel has the a property 'string Phone { get; set; }'.
The only way I've found to get AutoMapper to work is by changing the ViewModel Property to a backing property:
public long? Phone { get; set; }
public string PhoneNumberString
{
get
{
var srv = DependencyResolver.Current.GetService<IPhoneNumberService>();
return srv.GetFormattedPhoneNumber(Phone);
}
set
{
var srv = DependencyResolver.Current.GetService<IPhoneNumberService>();
Phone = srv.GetLongPhoneNumber(value);
}
}
And then in AutoMapper, have a gigantic line to call the constructor:
Mapper.Initialize(cfg =>
{
cfg.CreateMap<MyViewModel, MyDto>()
.ConstructUsing(src => new MyDto(
src.Phone
/* ...Some ~30 other parameters here... */))
.ReverseMap();
});
...There must be a better way to do this? I've tried these:
.ForSourceMember(x => x.PhoneNumberString, opt => opt.DoNotValidate())
and
.ForMember(x => x.PhoneNumberString, opt => opt.Ignore())
and
.ForMember(viewModel => viewModel.Phone, options => options.MapFrom<PhoneNumberResolver>());//PhoneNumberResolver implements IValueResolver<ProspectMaintenanceViewModel, ProspectMaintenanceDto, long?>
Which all give 'Core.DTO.MyDto needs to have a constructor with 0 args or only optional args.' when trying to map, and:
.ForMember(dest => dest.Phone, opt => opt.MapFrom(src => 5))
Which gives 'System.ArgumentException: 'Expression must be writeable' when trying to configure AutoMapper.
Is there some way I can make AutoMapper understand that it can entirely ignore PhoneNumberString (or, even better, some way by which I can make it map long? to string so I don't need the backing property) without having to use the dto's constructor?
Is there any special reason that requires your DTO to not have a default constructor?
I have all my fields as readonly so that I can include a constructor that modifies (e.g. 'Description = description?.Trim();') and validates (e.g. 'if (Phone.HasValue && Phone.ToString().Length != 10) throw ...') the parameters. This way I can ensure that the Dto, being a value object, is always in a valid state.
opt.Ignore()solution). - IshmaeelMapFromdocumentation (ResolveUsingin older Automapper versions) to get rid of thePhoneNumberStringbacking property. This feature allows you to map members of different types (or names) by using external conversion code. - Ishmaeel