2010-05-23 18 views
10

Uso frecuentemente AutoMapper para mapear objetos del Modelo (Dominio) a objetos ViewModel, que luego son consumidos por mis Vistas, en un patrón Modelo/Vista/Modelo de Vista.¿A dónde deberían ir las sentencias 'CreateMap'?

Esto implica muchas sentencias 'Mapper.CreateMap', que deben ejecutarse todas, pero solo deben ejecutarse una vez en el ciclo de vida de la aplicación.

Técnicamente, entonces, debería mantenerlos todos en un método estático en alguna parte, que se llama desde mi método Application_Start() (esta es una aplicación ASP.NET MVC).

Sin embargo, parece incorrecto agrupar una gran cantidad de problemas de mapeo juntos en una ubicación central.

Especialmente cuando el código de mapeo se vuelve complejo e implica el formateo y otra lógica.

¿Hay una mejor manera de organizar el código de mapeo para que se mantenga cerca del modelo de vista que le preocupa?

(me ocurrió una idea - con un método 'CreateMappings' en cada modelo de vista, y en el BaseViewModel, llamar a este método de creación de instancias Sin embargo, dado que el método sólo se debe llamar vez en el ciclo de vida de la aplicación,. necesita alguna lógica adicional para almacenar en caché una lista de tipos de ViewModel para los que se ha llamado al método CreateMappings y luego solo lo llama cuando sea necesario, para ViewModels que no están en esa lista.)

Respuesta

2

Si usa perfiles, puede colocar todas sus llamadas "CreateMap" allí. Además, puede crear una clase de bootstrapper estática que contenga su configuración y hacer que la pieza de inicio simplemente llame al programa de arranque.

+0

Pero eso no resuelve el problema de tener todas las asignaciones para todas las diferentes vistas-modelos agrupados juntos, cuando yo prefiero tener de alguna manera relacionados con las clases a las que se aplican. – Jonathan

0

bien, la forma en que actualmente lo estoy haciendo es la siguiente:

añado algo de lógica al constructor de mi BaseController, que se extiende método de las 'CreateMappings', pero sólo una vez por cada tipo de controlador:

public abstract class BaseController : Controller 
{  
    public BaseController() 
    { 
     if (!controllersWithMappingsCreated.Contains(GetType())) 
     { 
      CreateMappings(); 
      controllersWithMappingsCreated.Enqueue(GetType()); 
     } 
    } 

    protected virtual void CreateMappings() { } 
} 

En cada controlador concreto, utilizo CreateMappings para declarar las asignaciones para todos los modelos/modelos de vista relevantes para ese controlador.

public class AccountController : BaseController 
{ 
    public AccountController() : base() { } 

    protected override void CreateMappings() 
    { 
     Mapper.CreateMap<Models.User, ViewModels.UserProfile>(); 
     Mapper.CreateMap<Models.User, ViewModels.ChangePassword>(); 
    } 
} 

También encontré algunas alternativas interesantes que incluye ciertas cualidades here y here, sin embargo me parece que sea un poco demasiado complicado.

+2

Todavía tendría una clase de arranque automático estático, por lo que puede probar sus asignaciones. – Martin

+0

Buen trabajo. Pero, ¿qué es 'controllersWithMappingsCreated' en' BaseController'? – Blaise

6

Si realmente no desea usar un bootstrapper, al menos un constructor estático es una manera fácil de asegurar que su CreateMap se llame a lo sumo una vez. (Con menos jugar un poco más y la prueba del hilo de la respuesta de Jonathon.)

public class AccountController : Controller 
{ 
    static AccountController() 
    { 
     Mapper.CreateMap<Models.User, ViewModels.UserProfile>(); 
     Mapper.CreateMap<Models.User, ViewModels.ChangePassword>(); 
    } 
} 
+0

No he tenido suerte al colocar las asignaciones en el constructor estático. Encuentro que debo ponerlos en el constructor de la instancia. – AaronLS

+0

@AaronLS Oh no. ¿Recibes una excepción o algo así? ¿Qué clases usaste para los constructores y las asignaciones? –

Cuestiones relacionadas