[C#] AutoMapper desde ceros

Posted on Actualizado enn


Hola a todos, hoy vamos a ver una pequeña guía sobre AutoMapper, iniciando desde cómo instalarlo  y 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<Client> clients = new List<Client>() 
	{ 
		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<Client, ClientViewModel>();
		//Execute the mapping
		var clientViewModel = AutoMapper.Mapper.Map<Client, ClientViewModel>(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<Client, ClientViewModel>()
		.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, ClientViewModel>(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<Client, ClientViewModel>()
		.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.

Saludos.

7 comentarios sobre “[C#] AutoMapper desde ceros

    Gustavo Alzate Sandoval (ElTavo) escribió:
    02/03/2014 en 11:12

    Hola Julio, excelente artículo, muy detallada la explicación sobre autoMapper. saludos

    Juan Carlos Ruiz (@JuanKRuiz) escribió:
    02/03/2014 en 11:51

    Pinta bien, sin embargo me queda un par de dudas o apuntes.

    1. No me parecer que el nombre adecuado para el Tipo de Datos final deba terminar en ViewModel, porque eso hace que uno lo confunda con el ViewModel de MVVM, aunque segun se ve esto no es un requisito, sino más buscar una forma de nemotecnia.
    2. El problema que soluciona probablemente no sea el de seguridad, sino que su scope es mucho mayor, por ejemplo cuando uno crea colecciones de objetos con mucha información pero a la hora de enviarlos al cliente por ejemplo en JSON uno no necesita sino un par de atributos, allí usar el conversor sería de mucha utilidad, pues tuve casos que entre diferentes servicios de la App requerian toda la información serializada en JSON pero al momento de enviar a renderizar los datos solo se necesita una pequeña porción de esos datos por lo que es conveniente remapear en un tipo de dato más ligero o con fields nativos para asegurar la interoperabilidad.

      Julio Avellaneda respondido:
      02/03/2014 en 12:05

      Hola Juan, gracias por tu comentario, respecto a los puntos:
      1. Tu le puedes dar en nombre que quieras, lo importante es que sea claro, me.gusta usar con viewmodel ya que dicha clase generalmente la mapeo a una vista de MVC, así que tengo un modelo para mi vista
      2. El tema de seguridad es solo uno de los usos, depende de los requerimientos de tu aplicación, y en eso si que tu sabes, pero cuando se requiere serializar es un muy buen caso…

      Saludos

    sebastian escribió:
    02/08/2014 en 13:12

    hola julio: Excelente articulo , muy detallado la configuracion y el ejemplo , yo el automapper, lo lo baje de aca https://github.com/AutoMapper/AutoMapper , no podrias aconsejarme como bajar Nuget para añadirlo al visual , se podrá mapear de campos con datatables a objetos con automapper. Estuve buscando al respecto y no encontre algo util.
    Gracias.

      Julio Avellaneda respondido:
      02/09/2014 en 18:38

      Hola Sebastián, Nuget viene de fabrica con Visual Studio 2010 o superior, revisa si que lo tengas habilitado, en el menú herramientas lo puedes válidar, cualquier cosa me cuentas

    […] anteriormente hicimos una introducción a AutoMapper, vimos algunos conceptos básicos para rápidamente ponernos a tono con dicha herramienta y […]

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s