O AutoMapper é uma solução comum para isso, no entanto, prefiro codificar manualmente os mapeamentos. Eu normalmente tenho uma classe estática com métodos de extensão que mapeia para e de DTOs.
[DataContract]
class UserDto
{
[DataMember]
public string Name { get; set; }
[DataMember]
public DateTime BirthDay { get; set; }
}
class User
{
public string Name { get; private set; }
public DateTime BirthDay { get; private set; }
}
static class ContractMappings
{
public static UserDto ToDto(this User user)
{
return new UserDto
{
Name = user.Name,
BirthDay = user.BirthDay
};
}
}
Cada projeto nos limites do aplicativo terá uma classe ContractMappings
que contém mapeamentos para todos os contratos associados a esse projeto. Se esta classe ficar muito grande, pode ser um sinal de que os limites do projeto são inválidos.
Mapeamentos codificados manualmente permitem um maior grau de flexibilidade, o que pode ser uma vantagem e uma desvantagem.
No caso de ViewModels, geralmente, o ViewModel aceita um objeto DTO ou domínio em seu construtor. Se o ViewModel é usado para criar um DTO ou atualizar um objeto de domínio, eu coloco o método de atualização diretamente no ViewModel para manter o maior grau de coesão.