Hola a todos, hoy vamos a ver una pequeña guía sobre AutoMapper, iniciando desde cómo instalarloy mirando algunas de sus características.

AutoMapper básicamente es una herramienta que permite realizar un mapeo de un objeto a otro ahorrandonos gran cantidad de código y que provee algunas utilidades para personalizar cómo se realiza dicho mapeo entre objetos.

Realizar mapeo entre objetos en una funcionalidad común en muchos de nuestros desarrollos, ya que permiten personalizar la salida de los datos evitando revelar información confidencial y dando al cliente solo la información que él realmente necesita, basandonos en dicha afirmación, pensemos en una clase (modelo) Cliente que tiene campos como Id, nombre, apellido, edad, email, fecha de creación y clave entre otros, y ahora tenemos alguna funcionalidad que expone la información del cliente, en este caso estamos revelando información que no deberiamos entregar como la fecha de creación y la clave, en ese caso lo que podemos hacer es crear una nueva clase (conocída como ViewModel) con solo los campos que vamos a exponer; y aquí es donde AutoMapper juega un papel importante ya que nos va a ayudar a pasar de nuestro modelo/clase Cliente a nuestro ViewModel ClienteViewModel de una forma bastante sencilla y robusta.

Para ver como funciona AutoMapper vamos a partir de una aplicación Web con ASP.NET MVC, sin embargo es posible usarlo en cualquier otro tipo de aplicación.

Lo primero es la instalación, y como podrán adivinar tan solo debemos añadir AutoMapper haciendo uso de Nuget:

AutoMapper

Ahora vamos a crear el modelo, en este caso la clase Client:


 public class Client 
 { 
    public int ClientId { get; set; } 
    public string Name { get; set; } 
    public string LastName { get; set; } 
    public string Email { get; set; } 
    public string CreationDate { get; set; } 
    public string Password { get; set; } 
}

Como ya mencionamos, necesitamos un ViewModel, que no es más que otra clase con el nombre ClientViewModel:


public class ClientViewModel 
{ 
    public string Name { get; set; } 
    public string LastName { get; set; } 
    public string Email { get; set; } 
}

Ahora, vamos a crear una sencilla clase que va a actuar como repositorio y va a retornar un cliente (realmente un ClientViewModel) dado su id:


public class ClientRepository 
{ 
    private readonly List clients = new List() 
    { 
        new Client(){ ClientId = 1, Name = "Julio", LastName = "Avellaneda", Email="julito_gtu@hotmail.com", CreationDate = DateTime.Now, Password = "123456"} 
    }; 

    public ClientViewModel GetById(int id) 
    { 
        //Get the client 
        var client = clients[0]; 
        //Define the mapping 
        AutoMapper.Mapper.CreateMap(); 
        //Execute the mapping 
        var clientViewModel = AutoMapper.Mapper.Map(client); 
        //Return a viewmodel 
        return clientViewModel; 
    }
}

En el método anterior hacemos uso del método CreateMap de *AutoMapper.Mapper *para definir el mapeo de objetos, el primer parámetro es el objeto original (para el ejemplo Client) y el segundo parámetro es el objeto al cual se va a mapear (en este caso ClientViewModel), luego para que la magia funcione usamos el método Map para que se conviertan los objetos.

En el ejemplo anterior, AutoMapper realiza el mapeo entre las propiedades que tengan el mismo nombre y tipo de dato entre el modelo original y el ViewModel, razón por la cual poco hemos realizado en el método, sin embargo dicha premisa no se cumple siempre, ya que no en todos los casos las propiedades tienen el mismo nombre y puede existir alguna lógica adicional que se requiera implementar.

La siguiente imagen lo muestra claramente:

mappervm

Para casos más complejos que no cumplen la premisa básica del caso anterior, AutoMapper tiene una característica conocida como perfiles, y allí podemos definir un comportamiento más personalizado para los mapeos, para definir un perfil tenemos tres sencillos pasos:

  1. Crear una clase que herede de Profile (AutoMapper.Profile)
  2. Sobreescribir la propiedad ProfileName (Nombre del perfil)
  3. Sobreescribir el método Configure (Lógica del mapeo)

Entonces vamos a crear la clase CustomDto y realizamos los tres pasos anteriores, como nombre del perfil (propiedad ProfileName) definimos CustomDto, y por el momento vamos a dejar sin lógica el método Configure:


public class CustomDto : Profile 
{ 
    public override string ProfileName { get { return "CustomDto"; } } 

    protected override void Configure() { } 
}

Ahora vamos a centrarnos en el método Configure, de nuevo hacemos uso de AutoMapper.Mapper.CreateMap con objeto origen y objeto destino, y ahora para la personalización de como será llevado a cabo el mapeo entre los objetos, para ello hacemos uso del método ForMember, entonces para el ejemplo que veníamos trabajando el método Configure sería (por el momento no vamos a personalizar nada):


protected override void Configure() 
{ 
    Mapper.CreateMap() 
          .ForMember(d => d.Name, o => o.MapFrom(c => c.Name)) 
          .ForMember(d => d.LastName, o => o.MapFrom(c => c.LastName)) 
          .ForMember(d => d.Email, o => o.MapFrom(c => c.Email)); 
}

Ya que tenemos el perfil listo, ahora debemos llamarlo, y un buen lugar para hacerlo es en el evento Application_Start del Global.asax:


protected void Application_Start() 
{ 
    AreaRegistration.RegisterAllAreas(); 
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 
    RouteConfig.RegisterRoutes(RouteTable.Routes); 
    BundleConfig.RegisterBundles(BundleTable.Bundles); 
    AutoMapper.Mapper.Initialize(c => c.AddProfile(new CustomDto())); 
}

Ahora vamos a crear un nuevo método en la clase repositorio con el nombre GetByIdWithProfile para ver que para usar el perfil simplemente eliminamos la definición del mapeo:


public ClientViewModel GetByIdWithProfile(int id) 
{ 
    //Get the client 
    var client = clients[0]; 
    //Execute the mapping 
    var clientViewModel = AutoMapper.Mapper.Map(client); 
    //Return a viewmodel 
    return clientViewModel; 
}

Y si volvemos a probar efectivamente funciona sin problemas:

mappervm2

Hasta el momento se ha usado la funcionalidad por defecto de AutoMapper, así que vamos con el primer caso, en donde vamos a controlar cuando el valor de la propiedad origen es null, primero que pasa si por ejemplo la propiedad LastName no tiene un valor:

mappervmnull

Como podemos ver, la propiedad del ViewModel también tendrá el valor, así que por alguna regla de negocio, cuando el cliente no tiene un valor en LastName se debe mostrar el texto “-“, dicha regla de negocio la podriamos implementar en nuestra capa de UI o validando el valor de la propiedad antes de retornar el objeto… o aún mejor, en la definición del mapeo de AutoMapper, así que volvemos al método Configure y hacemos uso de NullSubstitute:


protected override void Configure() 
{ 
    Mapper.CreateMap() 
          .ForMember(d => d.Name, o => o.MapFrom(c => c.Name)) 
          .ForMember(d => d.LastName, o => o.NullSubstitute("-")) 
          .ForMember(d => d.Email, o => o.MapFrom(c => c.Email)); 
}

Y probando de nuevo:

mappervmnullsub

Otro caso típico, se da cuando necesitamos trabajar con colecciones de datos en lugar de 1 solo objeto, en este caso prácticamente es transparente el cambio, basta solo con especificar en el método Map que por ejemplo usaremos un IEnumerable, para mostrarlo de nuevo creamos un nuevo método en nuestra clase repositorio:


public IEnumerable<ClientViewModel> GetAll() 
{ 
    //Execute the mapping 
    var clientViewModel = AutoMapper.Mapper.Map<IEnumerable<Client>, IEnumerable<ClientViewModel>>(clients); 
    //Return a viewmodel 
    return clientViewModel;
}

Y de nuevo probando:

mappervmlist

Y por el momento vamos a dejar aquí, la idea del post era dar una rápida introducción a AutoMapper y creo que ha sido así, en próximos post veremos otras características de esta poderosa herramienta.

Descarga el ejemplo

Saludos.