2011-06-22 16 views
7

de dentro a fuera, estas son nuestras capas de aplicaciones MVC:ASP.NET MVC: ¿Dónde ensambla el modelo de vista para una vista?

  1. MS SQL/Tablas/Vistas/procedimientos almacenados
  2. Entity Framework 4.1 (ORM) con la generación POCO
  3. Repositorio
  4. servicio (recuperar) y Funciones de control (Guardar)
  5. Routing -> controlador -> Razor Ver
  6. (cliente) jQuery Ajax con Knockout.js (MVVM)

Todo está bien hasta que necesito para crear un único modelo de vista para el paso 5 para alimentar tanto a la vista de la maquinilla de afeitar, así como el JSON/Knockout ViewModel:

  • cabecera que incluye Desplegar opciones de la lista y las opciones para los campos siguientes
  • artículos - una serie de lo que enviamos al cliente que se convierte en el modelo de vista

Puesto que el controlador no tendrá acceso al repositorio directamente, Qué significa esto creo un servicio para cada un ¿Alguna vista que permita editar contenido? Necesitaré obtener el POCO del repositorio más todas las opciones para cada tipo de campo, según sea necesario.

Parece redundante crear servicios separados para cada vista. Por ejemplo, un modelo de vista para editar una dirección y un modelo de vista separado para editar una propiedad de bienes raíces que también tiene una dirección. Podríamos tener una docena de formularios que editen la misma dirección POCO.

Para hacer que esta pregunta sea más fácil de responder, ¿está permitiendo al controlador acceso directo a los repositorios una abstracción con fugas?

+0

¿Estás disfrutando de un golpe de gracia? Siempre he querido encontrar una razón para usarlo, y nunca lo hice. –

+0

@nathan Debes consultar este video http://channel9.msdn.com/events/mix/mix11/frm08. Ayudará a encontrar razones para usarlo. Reduce el código a aproximadamente la mitad. –

Respuesta

1

Bueno, ¿así que sus controladores tendrán un código que traduzca las POCO de Entity Framework en objetos de modelo de vista separados?

Si es así, debe mover ese código a una clase separada y seguir el principio de responsabilidad única. Si esa clase está en la "capa de servicio" o no depende de usted. Y si usa AutoMapper o no depende de usted. Pero este tipo de data mappers no debe ser parte de la lógica del controlador; los controladores deben ser tan tontos como sea posible.


OK, ahora vamos a pasar por alto el problema de asignación de datos, y pretender siempre se puede utilizar directamente como sus POCOs modelos de vista.De allí tendría que todavía desee una capa de servicio, ya que se traduciría entre

userService.GetByUserName("bob") 

en su controlador mudo, y poner en práctica que de manera específica mediante la devolución de

userRepository.Users.Single(u => u.UserName == "bob") 


Poniendo estos juntos, su UserController termina teniendo en IUserService y IUserDataMapper dependencias, y el código es súper tonto, como desee:

public ActionResult ShowUserPage(string userName) 
{ 
    var user = userService.GetByUserName(userName); 
    var viewModel = userDataMapper.MakeViewModel(user); 

    return View(viewModel); 
} 

Ahora puede probar el controlador con stubs para ambas dependencias o anular IUserDataMapper mientras se burla de IUserService, o viceversa. Su controlador tiene muy poca lógica, y has only one axis of change. Lo mismo puede decirse de la clase de mapeo de datos del usuario y la clase de servicio del usuario.


Estaba leyendo un artículo esta mañana que puede encontrar algo esclarecedor en estos asuntos de arquitectura. Es, condescendientemente, titulado "Software Development Fundamentals, Part 2: Layered Architecture". Probablemente no podrá cambiar de un modelo de aplicación de base de datos al modelo ignorante persistente que el artículo describe y sugiere. Pero podría indicarle la dirección correcta.

+0

Esa es la parte que me faltaba, para separar el Servicio que obtiene Entidades del mecánico que crea un modelo de vista de una colección de entidades. Supongo que el 'userDataMapper.MakeViewModel' podría consultar la base de datos para las posibles opciones de una lista desplegable, por ejemplo, para colocarla en el encabezado de viewModel. –

+0

Bueno, depende --- ¿quieres poder probar tu mapeador de datos sin una base de datos en vivo? Si es así, entonces el mapeador de datos probablemente debería ser inyectado con algún tipo de 'IOptionsConfiguration' o' IOptionsRepository'. Entonces el código relacionado en el mapeador de datos se convierte en 'options.GetUserTypes()' o lo que sea, y sus pruebas pueden resguardar esa interfaz según sea necesario. – Domenic

0

personalmente siempre inyecto el repositorio/repositorios en el controlador. No estoy seguro de por qué querría tener una capa de servicio entre el repositorio y el controlador. en todo caso, usaría las especificaciones.

una vez que haya hecho eso, consulte automapper. es un mapeador que, una vez configurado correctamente, puede asignar su modelo de dominio a su modelo de vista y viceversa.

+0

Cuidado, su mención de las especificaciones me hace pensar que está hablando de repositorios _Domain Driven Design_, mientras que la pregunta de OP parece indicar que está trabajando principalmente con una capa DTO anémica y el concepto de repositorio '_Patterns of Enterprise Application Architecture_. – Domenic

Cuestiones relacionadas