asp.net mvc - route - ¿Cómo está rellenando/validando sus ViewModels?
tag helper asp net core 2 (4)
Acabo de terminar un proyecto donde hicimos una variación en el # 4. Tuvimos una clase de servicio inyectada en el controlador. La clase de servicio tenía dependencias en el repositorio y una clase de generador de modelos (lo llamamos fábrica de modelos).
El controlador llamó a la clase de servicio, que manejó la lógica de validación comercial, y luego obtuvo los modelos de vista de la fábrica apropiada. Los modelos en sí mismos se basaron en anotaciones de datos para validación de entrada.
Funcionó muy bien para nuestro equipo. Hubo suficiente separación de preocupaciones para permitir a los desarrolladores hacer su trabajo sin afectarse unos a otros, pero fue lo suficientemente manejable como para entender lo que estaba sucediendo.
Es la primera vez que lo probamos y lo seguiremos. Me interesa ver cómo responden los demás.
Tengo curiosidad de todas las formas en que las personas construyen sus ViewModels y por qué eligen ese método.
Puedo pensar de varias maneras aquí:
-1. Repositorio inyectado: el controlador carga el modelo y se asigna al ViewModel. Aquí, el constructor de ViewModel podría tomar varias colecciones para establecerlas de forma interna para ex. en una lista de selección como:
public CustomerController(ISomeRepository repository)
{
_repository = repository;
}
public ActionResult Create()
{
CustomerCreateViewModel model = new CustomerCreateViewModel(_repository.GetShipTypes,
_repository.GetStates);
..
..
}
-2. ViewModelBuilder: ya sea inyectado o instanciado en el controlador con una instancia del repositorio inyectado. Llamado a través de algo así como
>var orderViewModel = orderViewModelBuilder.WithStates().Build(orderId);
o,
var orderViewModel = orderViewModelBuilder.WithStates().Build(orderId);
-3. Directamente en el controlador (no se requiere código - es complicado)
-4. Algún otro servicio (inyectado o no) que devuelve el modelo de dominio que luego asigna el controlador o un ViewModel (¿alguien hace esto para devolver un modelo de vista que no se nombra / anota específicamente como una clase de constructor ViewModel?)
public JobCreateViewModel BuildJobCreateViewModel(int parentId)
{
JobCreateViewModel model = new JobCreateViewModel();
model.JobStatus = _unitOfWork.JobRepository.GetJobStatuses();
model.States=_unitOfWork.StateRepository.GetAll();
return model;
}
Ahora en el viaje de regreso - en cuanto a la validación de sus modelos de vista - hereda de una clase base ViewModel para validaciones estándar, o copia sus validaciones (por ejemplo, atributos de anotación de datos) entre todos sus modelos de vista o simplemente confía en la validación del lado del servidor para que ¿Todos pueden ser validados contra su objeto de dominio?
¿Cualquier otro? ¿Algo mejor? ¿Por qué?
EDITAR Basado en un enlace a continuación, encontré un buen artículo de Jimmy Bogard sobre la arquitectura de ViewModels. Si bien no aborda la pregunta anterior directamente, es una gran referencia para cualquiera que venga aquí para obtener información de ViewModel. http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/
Inyecto un servicio en el controlador, no en un repositorio, y luego uso AutoMapper para convertirlo en un modelo de vista. El beneficio de la capa de servicio en este caso es que podría agregar múltiples operaciones simples de uno o más repositorios en una sola operación exponiendo un modelo de dominio. Ejemplo:
private readonly ICustomerService _service;
public CustomerController(ICustomerService service)
{
_service = service;
}
[AutoMap(typeof(Customer), typeof(CustomerViewModel))]
public ActionResult Create(int id)
{
Customer customer = _service.GetCustomer(id);
return View(customer);
}
en este ejemplo, AutoMap es un filtro de acción personalizado que puedo escribir, que se ejecuta después de la acción del controlador, inspecciona el objeto devuelto y utiliza asignaciones definidas de AutoMapper para asignarlo al tipo de destino especificado. Por lo tanto, la vista obtiene el ClienteViewModel correspondiente como tipo de modelo. Hubiera sido equivalente a:
public ActionResult Create(int id)
{
Customer customer = _service.GetCustomer(id);
CustomerViewModel vm = Mapper.Map<Customer, CustomerViewModel>(customer);
return View(vm);
}
es solo que es demasiada fontanería y un código repetitivo que podría centralizarse.
También te recomiendo que veas cómo ponen tus controladores en un video de dieta de Jimmy Bogard.
Nuestro método es inyectar el repositorio en el controlador y asignarlo a ViewModel usando Automapper http://automapper.org/ . Nuestros ViewModels contienen atributos de anotación de datos para permitir que la validación ocurra en el cliente.
Llamamos a métodos en el repositorio que devuelven objetos de dominio (Entity Framework). Los objetos de dominio se asignan a ViewModel. Tendemos a usar el mismo modelo de vista para ediciones y agregaciones para que las anotaciones de datos sean necesarias una vez. En su forma más simple se ve como el siguiente código:
public ActionResult List(int custId, int projId)
{
var users = _userRepository.GetByCustomerId(custId);
var userList = Mapper.Map<IEnumerable<CMUser>, IEnumerable<UserListViewModel>>(users);
return View(userList);
}
Utilizo una capa de servicio que oculta el modelo de dominio del controlador y devuelve ViewModels de los métodos de servicio. Esto me permite realizar cambios en el modelo de dominio sin afectar al cliente.