2009-08-18 17 views
23

Actualmente estoy pasando mis objetos de dominio a mis vistas y vinculándolos directamente desde los POST. Todo el mundo dice que esto es malo, así que estoy intentando agregar el concepto de ViewModel.usando ViewModels para acciones POST en MVC elegantemente

Sin embargo, no puedo encontrar una manera de hacerlo de forma muy elegante, y me gustaría saber qué soluciones tienen otras personas para no terminar con una acción de controlador muy desordenada.

el proceso típico para decir algo de "añadir persona" funcionalidad se ve así:

  1. realizar una solicitud GET para una vista que representa un modelo de vista Persona en blanco
  2. segundo palo (de) datos válidos
  3. controlador vincula datos publicados en una persona viewmodel
  4. si falla el enlace, tengo que hacer la misma acción que en (1) pero con algunos datos, no un objeto en blanco y errores
  5. si se realizó el enlace, yo necesite asignar las propiedades de la máquina virtual en un modelo real
  6. validar el modelo
  7. si la validación pasó: salvar a la persona, comprometerse, mapear los datos de los usuarios a una pantalla VM y devolverlo en una vista
  8. si la validación fallado, haga las mismas acciones que en (1) pero con algunos datos y errores

Hacer todo esto en una acción de controlador (ignorando el GET) ciertamente no es SRP o DRY.

Estoy tratando de pensar en una forma de romper este proceso para que cumpla con SRP, es limpio, modular y, sobre todo, comprobable.

¿Qué es la solución de personas a esto?

He estado experimentando con invocadores de acción-controlador personalizados para separar las preocupaciones en métodos individuales, encuadernadores inteligentes y simplemente fuerza bruta, pero aún no he encontrado una solución que me satisfaga.

P.S. ya que añade tanta complejidad, convencerme de eso que aún tiene que molestarse

+0

¿Qué le termina haciendo? –

+1

nada todavía :(todavía estoy tratando de decidir sobre una solución elegante para que mis controladores no terminen realmente abarrotados. Creo que la verdadera respuesta es openrasta. –

+0

Quizás estas publicaciones puedan ayudar un poco: http://stackoverflow.com/a/25460769/3969501, http://stackoverflow.com/a/25169023/1475331 –

Respuesta

2

El (ViewModel) patrón MVVM es definitivamente el uno para ir, que tenía una pregunta similar acerca de la publicación de nuevo a una acción hace unos días - aquí es el enlace: MVVM and ModelBinders in the ASP.NET MVC Framework

El resultado fue que puede usar el atributo Vincular para publicar de nuevo el tipo complejo que desea.

6

He sentido la misma incomodidad. Mi única manera alrededor de ella ha sido la de hacer lo siguiente:

  1. Crear un aglutinante para unir y validar el modelo de vista
  2. Crear una carpeta para obtener la entidad de la base de datos (o simplemente hacer esto en el controlador)
  3. Llamar a un método heredado Guardar en la superclase. Este método toma el modelo de vista y la entidad que se actualizará, y hace todo el trabajo que enumeró en sus pasos.

El método de acción se ve así:

public ActionResult Whatever(TViewModel viewModel, TEntity entity) 
{ 
    return Save(viewModel, entity); 
} 

El controlador de base tiene una definición genérica, así:

public abstract BaseController<TEntity, TViewModel> 
    where TEntity : Entity 
    where TViewModel : ViewModel 

El constructor tiene dos dependencias, una para el repositorio de entidad y otro para el mapeador de modelos, así:

protected BaseController(IRepository<TEntity> repository, IMapper<TEntity, TViewModel> mapper) 

Con esto en su lugar, a continuación, puede escribir un método Save protegida que se puede llamar desde las acciones del controlador en la subclase, así:

protected ActionResult Save(TViewModel viewModel, TEntity entity) 
{ 
    if (!ModelState.IsValid) 
     return View(viewModel); 

    _mapper.Map(viewModel, entity); 
    if (!entity.IsValid) 
    { 
     // add errors to model state 
     return View(viewModel); 
    } 

    try 
    { 
     _repository.Save(entity); 
     // either redirect with static url or add virtual method for defining redirect in subclass. 
    } 
    catch (Exception) 
    { 
     // do something here with the exception 
     return View(viewModel); 
    } 
} 

En cuanto a la capacidad de prueba, se puede probar el método Save pasando válida/modelos y entidades de vista no válida. Puede probar la implementación del mapeador de modelos, el estado válido del modelo de vista y el estado válido de la entidad por separado.

Al hacer que el controlador base sea genérico, puede repetir este patrón para cada entidad/combo viewmodel en su dominio, si está creando muchos controladores para hacer lo mismo.

Estoy muy interesado en escuchar lo que otros tienen que decir al respecto. Gran pregunta

+0

ideas interesantes +1 –

+2

Ideas definitivamente interesantes, pero OpenRASTA sigue siendo una mejor opción :) – Dve

0

tengo muchas buenas soluciones en la aplicación de ejemplo mvc asp.net que está en el download of valueinjecter (mapeador que utilizo para mapear ViewModels a/desde las entidades, también se puede asignar FormCollection/Solicitud de Entidades)

aquí está uno:

public class TinyController :Controller 
     { 
      private readonly IModelBuilder<Person, PersonViewModel> modelBuilder; 

      public TinyController() 
      { 
       modelBuilder = new PersonModelBuilder(); 
      } 

      public ActionResult Index() 
      { 
       return View(modelBuilder.BuildModel(new PersonRepository().Get())); 
      } 

      [HttpPost] 
      public ActionResult Index(PersonViewModel model) 
      { 
       if (!ModelState.IsValid) 
        return View(modelBuilder.RebuildModel(model)); 

        var entity = modelBuilder.BuildEntity(model); 
... 
//save it or whatever 
      } 
     } 
Cuestiones relacionadas