net mvc form editar asp asp.net-mvc viewmodel

asp.net-mvc - form - razor mvc model



Uso de ViewModels para acciones POST en MVC con elegancia (3)

Actualmente, estoy pasando los objetos de mi dominio a mis vistas y los vinculo directamente a ellos desde POST. Todos dicen que esto es malo, así que estoy intentando agregar el concepto de ViewModel.

Sin embargo, no puedo encontrar la manera de hacerlo de manera muy elegante, y me gustaría saber cuáles son las soluciones de otras personas para no terminar con una acción de controlador muy desordenada.

El proceso típico para decir alguna funcionalidad de "agregar persona" se ve así:

  1. realizar una solicitud GET para una vista que representa un modelo de vista de Persona en blanco
  2. publicar de nuevo (in) datos válidos
  3. El controlador vincula los datos publicados en un modelo de persona.
  4. Si el enlace falla, debo hacer la misma acción que en (1) pero con algunos datos, no un objeto en blanco y errores
  5. Si el enlace se realizó correctamente, necesito asignar las propiedades de la máquina virtual a un modelo real
  6. validar el modelo
  7. Si la validación fue aprobada: guardar la persona, confirmar, asignar los detalles de los usuarios a una VM de pantalla y devolverla en una vista
  8. si la validación falló, realice las mismas acciones que en (1) pero con algunos datos y errores

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

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

¿Cuáles son las soluciones de los pueblos a esto?

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

PD, ya que agrega tanta complejidad, me convence de por qué incluso necesito molestar


El patrón de MVVM (ViewModel) es definitivamente el elegido, tuve una pregunta similar acerca de POSTing a una acción hace unos días. Aquí está el enlace: MVVM y ModelBinders en ASP.NET MVC Framework.

El resultado fue que puede utilizar el atributo Bind para devolver el tipo complejo que desea.


He sentido la misma incomodidad. Mi única forma de hacerlo ha sido hacer lo siguiente:

  1. Crear un cuaderno para enlazar y validar el modelo de vista.
  2. Cree un cuaderno para obtener la entidad de la base de datos (o simplemente haga esto en el controlador)
  3. Llame a un método Guardar heredado en la superclase. Este método toma el modelo de visualización y la entidad que se actualizará, y realiza 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 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 entidades y otra para el mapeador de modelos, como por ejemplo:

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

Con esto en su lugar, puede escribir un método de Guardar protegido que se puede llamar desde las acciones del controlador en la subclase, de esta manera:

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, puede probar el método de guardar pasando modelos y entidades de vista válidos / no válidos. 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 combinación de entidad / modelo de vista en su dominio, si está creando muchos controladores para hacer lo mismo.

Estoy muy interesado en escuchar lo que otros tienen que decir sobre esto. Gran pregunta


Tengo muchas buenas soluciones en la aplicación de muestra mvc de asp.net que se encuentra en la descarga de valueinjecter (el mapeador que uso para asignar ViewModels a / desde Entidades, también puede asignar FormCollection / Request to Entities)

Aquí hay 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 } }