Desenvolvimento Back-end C#

Utilizando AutoMapper no C#

Conheça a biblioteca AutoMapper e aprenda como implementá-la em uma aplicação C#.

há 4 anos 3 semanas

Formação Desenvolvedor C#
Conheça a formação em detalhes

Ao criar uma aplicação, a recomendação mais ouvida (e que deveria ser a mais seguida) é a separação de responsabilidade entre as camadas do sistema. Existem vários padrões de projetos que auxiliam na implementação deste processo, sendo MVC o mais popular. Hoje há uma infinidade de frameworks baseados neste padrão.

Entretanto em algumas situações apenas ele não garante isso, pode ser necessário ter um desacoplamento maior entre as camadas. Para facilitar este processo, temos o AutoMapper.

AutoMapper

O AutoMapper é uma biblioteca open-source criada por Jimmy Bogard para resolver um problema enganosamente complexo, que é o mapeamento de um objeto para outro. Este tipo de tarefa geralmente é chata e tediosa, então esta pequena biblioteca foi criada para resolver esta situação de forma simples.

C# (C Sharp) - ASP.NET MVC
Curso C# (C Sharp) - ASP.NET MVC
Conhecer o curso

Mapeando uma Model para uma ViewModel

O AutoMapper é mais utilizado em aplicações ASP.NET MVC, principalmente quando esta aplicação faz uso do padrão MVVM (Model-View-ViewModel), mas como pode ser utilizado em qualquer tipo de aplicação e para facilitar a explicação, aqui veremos os exemplos do uso desta biblioteca em uma aplicação console simples.

Entretanto, antes de vermos o AutoMapper na prática, vamos compreender o problema que resolve.

Ao implementar padrão MVVM, haverão duas classes com características equivalentes: uma que refletirá o domínio, e.g, uma entidade do Entity Framework; e outra que refletirá a View, a interface da aplicação. Para ilustrar isso, imagine uma entidade Cliente:

public class Cliente
{
    public long Id { get; set; }
    public string Nome { get; set; }
    public string Sobrenome { get; set; }
    public DateTime DataNascimento { get; set; }
    public double Renda { get; set; }

    public override string ToString()
		=> $"{Id} - {Nome} - {Sobrenome} - {DataNascimento} - {Renda}";
}

Na interface de visualização dos clientes, não deve ser exibido a renda. Desta forma, cria-se uma ViewModel com a seguinte estrutura:

public class ClienteListViewModel
{
    public long Id { get; set; }
    public string Nome { get; set; }
    public string Sobrenome { get; set; }
    public DateTime DataNascimento { get; set; }

    public override string ToString()
		=> $"{Id} - {Nome} - {Sobrenome} - {DataNascimento}";
}

Para mapear os dados de Cliente para ClienteListViewModel, podemos fazê-lo manualmente da seguinte forma:

static void Main(string[] args)
{
    var cliente = new Cliente()
    {
        Id = 1,
        Nome = "Carlos",
        Sobrenome = "Silva",
        DataNascimento = new DateTime(1980, 03, 12),
        Renda = 4012.04
    };
    var clienteViewModel = new ClienteListViewModel()
    {
        Id = cliente.Id,
        Nome = cliente.Nome,
        Sobrenome = cliente.Sobrenome,
        DataNascimento = cliente.DataNascimento
    };

    Console.WriteLine(clienteViewModel);
    Console.ReadLine();
}

Algo simples. Agora imagine ter que trabalhar com uma entidade que possui vinte propriedades, caso haja muitos registros, ou mesmo, com várias entidades implementando o padrão MVVM? É possível ver que este tipo de tarefa simples pode se tornar complicado com adição de poucos detalhes.

É para facilitar este tipo de ação que o AutoMapper foi criado.

AutoMapper vem ao resgate

Para utilizar esta biblioteca em um projeto é necessário adicioná-la via NuGet:

dotnet add package AutoMapper

Na sua utilização básica, é necessário criar uma configuração que indica como as classes são mapeadas:

var configuration = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<Cliente, ClienteListViewModel>();
});

Em CreateMap deve ser informado a classe de origem dos objetos (Cliente) e a classe de destino (ClienteListViewModel). Caso também seja realizado o mapeamento inverso, isso deve ser informado nesta configuração:

var configuration = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<Cliente, ClienteListViewModel>();
    cfg.CreateMap<ClienteListViewModel, Cliente>();
});

A partir da configuração cria-se um objeto Mapper:

var mapper = configuration.CreateMapper();

Que irá aplicar o mapeamento:

var clienteViewModel = mapper.Map<ClienteListViewModel>(cliente);

Perfis de entidade

Como as ViewModels refletem as interfaces da aplicação, em alguns projetos uma entidade pode gerar várias ViewModels. Para facilitar a organização dos mapeamentos dessas ViewModels, o AutoMapper permite a criação de perfis (Profile) para uma entidade:

public class ClienteProfile: Profile
{
    public ClienteProfile()
    {
        CreateMap<Cliente, ClienteListViewModel>();
        CreateMap<ClienteListViewModel, Cliente>();
    }
}

Com isso, na hora de criar a configuração, indica-se o perfil da entidade:

var configuration = new MapperConfiguration(cfg =>
{
    cfg.AddProfile<ClienteProfile>();
});

Outra vantagem de se utilizar perfis é que pode ser informado o assembly da aplicação:

var configuration = new MapperConfiguration(cfg =>
{
    cfg.AddMaps(typeof(Program).Assembly);
});

E o AutoMapper irá analisa-lo para carregar os perfis definidos no código. Este tipo de recurso é muito útil quando a aplicação define vários perfis de entidade.

Mapeamento customizado

Caso ambos os objetos possuam propriedades com os mesmos nomes, como no nosso exemplo até o momento, o mapeamento do AutoMapper é automático, mas pode haver situações onde isso não ocorre.

Por exemplo, vamos modificar a nossa classe ClienteListViewModel para o código abaixo:

public class ClienteListViewModel
{
    public long Id { get; set; }
    public string NomeCompleto { get; set; }
    public DateTime DataNascimento { get; set; }

    public override string ToString()
		=> $"{Id} - {NomeCompleto} - {DataNascimento}";
}

Isso não irá gerar erro no nosso projeto, mas a biblioteca não saberá mapear o valor de NomeCompleto, assim esta propriedade não receberá nenhum dado.

Então é necessário informar como essa propriedade deve ser mapeada:

CreateMap<Cliente, ClienteListViewModel>()
    .ForMember(dst => dst.NomeCompleto,
                    map => map.MapFrom(src => $"{src.Nome} {src.Sobrenome}"));

Acima estamos dizendo que a propriedade NomeCompleto em ClienteListViewModel deve ser mapeada para os valores de Nome e Sobrenome de Cliente.

ASP.NET Core  - Desenvolvimento de APIs REST
Curso ASP.NET Core - Desenvolvimento de APIs REST
Conhecer o curso

Conclusão

O uso básico da biblioteca AutoMapper é muito simples, o que facilita a adoção do padrão MVVM. Além disso, mesmo sendo pequena, possui muitos recursos, que não foram abordados por completo aqui.

Existem outras bibliotecas que realizam este tipo de procedimento, mas caso necessite fazer este tipo de mapeamento no seu projeto, ou esteja pensando em desacoplar as camadas da sua aplicação, o AutoMapper é uma ótima pedida.

Por hoje é só! Até a próxima :)

Autor(a) do artigo

Wladimilson M. Nascimento
Wladimilson M. Nascimento

Instrutor, nerd, cinéfilo e desenvolvedor nas horas vagas. Graduado em Ciências da Computação pela Universidade Metodista de São Paulo.

Todos os artigos

Artigos relacionados Ver todos