2010-06-08 11 views
53

Digamos que tiene un proyecto ASP.NET MVC y está utilizando una capa de servicio, como en este gestor de contactos de tutorial en el sitio asp.net: http://www.asp.net/mvc/tutorials/iteration-4-make-the-application-loosely-coupled-cs¿Debería una capa de servicio devolver modelos de vista para una aplicación MVC?

Si tiene ViewModels para sus puntos de vista, es la capa de servicio de la lugar apropiado para proporcionar cada modelo de vista? Por ejemplo, en el ejemplo de código capa de servicio hay un método

public IEnumerable<Contact> ListContacts() 
    { 
     return _repository.ListContacts(); 
    } 

Si por el contrario quieres un IEnumerable, en caso de ir en la capa de servicio, o hay alguna otra parte que es la "correcta" lugar?

¿Quizás más apropiado, si tiene un modelo de vista separado para cada vista asociada con ContactController, debe ContactManagerService tener un método diferente para devolver cada modelo de vista? Si la capa de servicio no es el lugar correcto, ¿dónde deberían inicializarse los objetos de modelo de vista para que los use el controlador?

+0

Es posible que también desee echar un vistazo a http://weblogs.asp.net/scottgu/archive/2009/04/28/free-asp-net-mvc-nerddinner-tutorial-now-in-html. aspx –

+3

El tutorial de NerdDinner es el peor lugar para buscar esta información. Es genial para demostrar las características de MVC, pero la arquitectura que implica es horrible. – Aaronaught

+1

@Aaronaught ya que al parecer eres un experto, ¿cuál es tu tutorial en profundidad sobre la arquitectura correcta de MVC? –

Respuesta

37

En general, no.

Ver modelos están destinados a proporcionar información hacia y desde puntos de vista y debe ser específico para la aplicación, en comparación con el dominio general. Los controladores deben orquestar la interacción con repositorios, servicios (estoy haciendo algunas suposiciones de la definición de servicio aquí), etc. y manejar la construcción y validación de modelos de vista, y también contener la lógica de determinación de vistas para renderizar.

por fugas de modelos de vista en una capa de "servicio", que están borrando sus capas y ahora tienen posible aplicación y presentación específica mezclado con lo que debería centrado con responsabilidades a nivel de dominio.

+0

Tom: en el ejemplo, el método Index() del controlador construye la vista que devuelve del método ListContacts() mostrado arriba, que devuelve un IEnumberable , ¿entonces no está el modelo de vista filtrando en la "capa de servicio"? ¿Es este un mal ejemplo? Y si es así, ¿dónde está el lugar apropiado para inicializar viewmodels para consumo según las diversas vistas del controlador? – erg39

+0

@ erg39: ¿No está en contacto con un tipo de modelo de dominio? Si es así, entonces no. Es posible que tenga algo similar a un contacto para su modelo de vista, pero también puede tener información adicional específica para una sola vista o conjunto de vistas. Contact no sabe (o no debería) nada sobre detalles particulares de una vista. – captaintom

+1

@ erg39: en cuanto a la inicialización de modelos de vista, el controlador tiene la responsabilidad de construir nuevas instancias de modelos de vista y validar/validar modelos de vista recibidos de la vista. – captaintom

5

supongo que depende de lo que se tiene en cuenta los "servicios" a ser. Nunca me ha gustado el término service en el contexto de una sola clase; es increíblemente vago y no dice mucho sobre el propósito real de la clase.

Si la "capa de servicio" es una capa física, tales como un servicio web, a continuación, en absoluto; los servicios en un contexto SOA deben exponer las operaciones de dominio/negocio, no los datos y no la lógica de presentación. Pero si el servicio se acaba de utilizar como concepto abstracto para un mayor nivel de encapsulado, no veo ningún problema con su uso de la forma en que lo desea.

Simplemente no mezcle conceptos. Si el servicio se ocupa de modelos de vista, entonces debería ser un servicio de presentación y ser en capas sobre la parte superior del modelo real, sin tocar directamente la base de datos o cualquier lógica de negocio.

+0

En la muestra, la "capa de servicio" es una abstracción entre el controlador y una capa de repositorio cuya intención declarada debe usarse para la validación antes de pasar datos al repositorio. También contiene el método ListContacts() anterior, así como un método GetContact() para obtener un único objeto de contacto que el controlador utiliza para las vistas vinculantes. Entonces, parece que parece apropiado que dicha capa de servicio conozca la lista de modelos de vista que podría necesitar un controlador completamente desarrollado, ¿correcto? – erg39

+0

@ erg39: si su servicio está haciendo la validación, es fundamentalmente parte del modelo. No maneja la lógica de presentación y no debe combinarse con modelos de vista. – Aaronaught

+0

@Aaronaught: ¿Dónde dirías que sería el lugar apropiado para inicializar viewmodels? ¿Debería ser solo una abstracción separada, como una "capa de servicio de viewmodel"? – erg39

21

No, no lo creo. Los servicios solo deben preocuparse por el dominio del problema, no por la vista que rinde resultados. Los valores devueltos deben expresarse en términos de objetos de dominio, no de vistas.

16

Según el enfoque tradicional o teoría sabia, ViewModel debe ser parte de capa de interfaz de usuario. Al menos el nombre lo dice.

Pero cuando se llega a la implementación de usted mismo con Entity Framework, MVC, depósito, etc., entonces te das cuenta de algo más.

Alguien tiene que asignar Modelos Entidad/DB con ViewModels (DTO menciona en el final). ¿Debería hacerse esto en [A] la capa UI (por el Controlador), o en [B] la capa Servicio?

Voy con la opción B.La opción A es un no no por el simple hecho de que varios modelos de entidades se combinan para formar un ViewModel. Es posible que no pasemos datos innecesarios a la capa UI, mientras que en la opción B, el servicio puede jugar con datos y pasar solo el nivel requerido/mínimo a la capa UI después del mapeo (al ViewModel).

De nuevo, vamos a ir con la opción A, poner ViewModel en la capa de UI (y el modelo de entidad en la capa de Servicio).

Si la capa de servicio necesita correlacionarse con el modelo de vista, entonces la capa de servicio necesita acceder a ViewModel en la capa de interfaz de usuario. ¿Qué biblioteca/proyecto? El modelo de vista debe estar en un proyecto separado en la capa de la interfaz de usuario, y este proyecto debe ser referenciado por la capa de servicio. Si ViewModel no está en un proyecto separado, entonces hay una referencia circular, así que no vayas. Parece incómodo tener la capa de servicio accediendo a la capa de interfaz de usuario, pero aún así podemos hacer frente a ella.

Pero, ¿qué ocurre si hay otra aplicación UI que utiliza este servicio? ¿Qué pasa si hay una aplicación móvil? ¿Qué tan diferente puede ser ViewModel? ¿Debe el Servicio acceder al mismo proyecto de modelo de vista? ¿Todos los proyectos de UI accederán al mismo proyecto de ViewModel o tendrán el suyo propio?

Después de estas consideraciones, mi respuesta sería poner el proyecto Viewmodel en la Capa de servicio. ¡Cada capa de interfaz de usuario tiene que acceder a la capa de servicio de todos modos! Y podría haber muchos ViewModels similares que todos podrían usar (por lo tanto, la asignación se vuelve más fácil para la capa de servicio). Las asignaciones se realizan a través de linq en estos días, lo cual es otra ventaja.

Por último, hay esta discusión sobre DTO. Y también sobre la anotación de datos en ViewModels. Los modelos ViewModels con anotaciones de datos (Microsoft.Web.Mvc.DataAnnotations.dll) no pueden residir en la capa de servicio sino que residen en la capa UI (pero ComponentModel.DataAnnotations.dll puede residir en la capa de servicio). Así que DTO en realidad es un ViewModel porque en su mayoría habrá un mapeo uno a uno entre los dos (digamos con AutoMapper). Una vez más, DTO sigue teniendo la lógica necesaria para la interfaz de usuario (o múltiples aplicaciones) y reside en la capa de servicio. Y la capa de interfaz de usuario ViewModel (si usamos Microsoft.Web.Mvc.DataAnnotations.dll) es solo para copiar los datos de DTO, con algunos 'comportamientos'/atributos añadidos.

[Ahora bien, esta discusión está a punto de dar un giro interesante leer sobre ...: I]

Y no creo que los atributos de anotación de datos son sólo para la interfaz de usuario. Si limita la validación utilizando System.ComponentModel.DataAnnotations.dll , entonces el mismo modelo de vista también se puede usar para la validación de back-end front-end & (eliminando así UI-residing-viewmodel-copy-of-DTO). Más de los atributos también se pueden usar en modelos de entidades. Por ejemplo, al utilizar .tt, los modelos de datos de Entity Framework pueden autogenerarse con atributos de validación para realizar algunas validaciones de db, como max-length, antes de enviarlas al back-end. Otra ventaja es que si la validación de back-end cambia en DB, entonces .tt (lee las especificaciones de db y crea un atributo para la clase de entidad) lo recogerá automáticamente. Esto puede obligar a las pruebas de la unidad de validación UI a fallar también, lo cual es una gran ventaja (para que podamos corregirlo e informar a todas las UI/consumidores en lugar de olvidar y fallar accidentalmente). Sí, la discusión se está moviendo hacia un buen diseño del marco. Como puede ver, todo está relacionado: validación de nivel, estrategia de prueba de unidad, estrategia de almacenamiento en caché, etc.

Aunque no está directamente relacionado con la pregunta. 'ViewModel Façade' mencionado en esto debe mirar channel 9 link también vale la pena explorar. Comienza exactamente a los 11 minutos y 49 segundos en el video. Porque este sería el próximo paso/pensamiento una vez que se resuelva su pregunta actual dada arriba: '¿Cómo organizar viewmodels?'

También en su ejemplo "_repository.ListContacts()" está devolviendo un modelo de vista del repositorio. Esta no es una forma madura. Los repositorios deben proporcionar modelos de entidades o modelos db. Esto se convierte para ver modelos y es este modelo de vista el que devuelve la capa de servicio.

+0

¿No está introduciendo una capa de Aplicación el movimiento correcto aquí? mapearía viewmodels y entidades de dominio, manteniéndose mutuamente independientes y felices. – sergio

+0

Viewmodels y entidades de dominio son independientes de todos modos. ¿La "capa de aplicación" es una nueva capa solo para mapear entidades? ¿Has pensado también en la capa de interfaz de usuario y el servicio para acceder a esta capa de aplicación? porque al final todavía necesitan acceder a sus modelos. O en otras palabras, ¿qué resolvería una capa adicional? –

4

Esto ha venido un poco "depende" donde trabajo - generalmente hemos tenido un controlador consumiendo algunos servicios - luego combinando DTO devuelto en un 'ViewModel' que luego se pasaría al cliente - ya sea a través del resultado JSON o vinculado en la Plantilla Razor.

La cosa es, alrededor del 80% del tiempo - el mapeo de DTO a ViewModel ha sido 1-1. Estamos empezando a avanzar hacia 'Donde sea necesario, simplemente consuma el DTO directamente, pero cuando el DTO y lo que necesitamos en nuestro cliente/vista no coinciden, entonces creamos un ViewModel y hacemos la asignación entre objetos según sea necesario'.

Aunque todavía no estoy convencido de que esta sea la mejor o la mejor solución, ya que termina llevando a acaloradas discusiones acerca de si estamos agregando X al DTO para satisfacer las necesidades de la vista.

+1

Si mantiene DTO en la capa de servicio y lo usa como un modelo de vista en la interfaz de usuario, ¿dónde pone la validación (DataAnnotation, FluentValidation u otra cosa)? Estoy en la misma situación de "80% 1: 1 DTO a VM", por lo que no estoy seguro de qué hacer. – Iztoksson

Cuestiones relacionadas