Я хотел бы использовать AutoMapper и предоставить некоторые значения во время выполнения.
Например, у меня есть DTO & ViewModel.
Одно из свойств не существует в DTO и не может быть отображенонепосредственно с помощью Конвертеров / Резолверов / Трансформаторов;
namespace Lab.So.Sample
{
public class UserDto
{
public int UserId { get; set; }
public string UserCode { get; set; }
}
public class UserGroupDto
{
public List<UserDto> Users { get; set; }
}
public class UserViewModel
{
public int UserId { get; set; }
public string FullName { get; set; }
}
public class UserGroup
{
public List<UserViewModel> Users { get; set; }
}
class Program
{
static void Main(string[] args)
{
var src = new Fixture().Create<UserGroupDto>();
Mapper.Initialize(cfg =>
{
cfg.CreateMissingTypeMaps = true;
cfg.ValidateInlineMaps = false;
});
// How to hook mapping of nested object User->UserViewModel to provide value of FullName in runtime
var dst = Mapper.Map<UserGroupDto, UserGroup>(src);
}
}
}
У меня есть какой-то обходной путь, как это сделать, но это не удобно для человека, как для меня:
class Program
{
internal class UserViewModelFullNameResolver : IValueResolver<UserDto, UserViewModel, string>
{
public string Resolve(UserDto source, UserViewModel destination, string destMember, ResolutionContext context)
{
var names = context.Items["ctx.Names"] as IDictionary<int, string>;
if (names == null || !names.TryGetValue(source.UserId, out var fullName))
{
return null;
}
return fullName;
}
}
static void Main(string[] args)
{
var src = new Fixture().Create<UserGroupDto>();
Mapper.Initialize(cfg =>
{
cfg.CreateMissingTypeMaps = true;
cfg.ValidateInlineMaps = false;
cfg.CreateMap<UserDto, UserViewModel>()
.ForMember(d => d.FullName, opt => opt.MapFrom<UserViewModelFullNameResolver>());
});
var names = new Dictionary<int, string>
{
{ 10, "FullName-10" },
{ 20, "FullName-20" },
};
var dst = Mapper.Map<UserGroupDto, UserGroup>(src, opt=>opt.Items["ctx.Names"] = names);
}
}
В этом обходном пути большинствонеудобно согласование имен ключей в opt.Items;Если что-то случайно сделало опечатку, это трудно исследовать и исправить;
Я выглядел примерно так:
var dst = Mapper.Map<UserGroupDto, UserGroup>(src, opt=>opt.Use(new UserViewModelFullNameResolver());
Другими словами, это определение экземпляра распознавателя во время выполнения для каждого уникального случая;
Также я бы согласился, если бы у меня была возможность определить крюк для отображения определенного типа в графе объектов:
var dst = Mapper.Map<UserGroupDto, UserGroup>(src, opt=>opt.Hook<UserDto,UserViewModel>((s,d)=> { /* any logic to read external data */ });
Пример использования:
var srcA = readDataA();
var srcB = readDataB();
var dst = Mapper.Map<UserGroupDto, UserGroup>(
src,
opt=>opt.Hook<UserDto,UserViewModel>(
(s,d)=>
{
d.FullName = srcA + srcB;
});
Пожалуйста, предложите что-нибудь, что поможет считывать данные для выполнения сопоставления в тех случаях, когда в источнике нет всех необходимых данных для вложенного объекта в месте назначения.