2010-08-10 6 views
6

Mis controladores se están volviendo grandes y fuera de control.Algunas de las mejores prácticas de Asp.NET MVC2 para administrar controladores de grasa en una capa de servicio empresarial

Un controlador típico realiza lo siguiente:

  • determina si un usuario dado tiene acceso a un recurso dado.
  • Valida el ViewModel.
  • Traduce el modelo de vista en el modelo DTOM para persistencia.
  • Llama a los repositorios para actualizar/crear nuevos objetos y otros objetos nuevos asociados.
  • Accede a datos en múltiples clases de ayuda del repositorio
  • Comprueba si los usuarios se notifican.
  • Se llama ayudantes para enviar mensajes de correo electrónico
  • Se registra datos a la base de datos a través de otro repositorio de objetos
  • etc ...

En resumen, orquestan una gran cantidad de cosas. Me gustaría mover todo a una capa de Servicios, pero realmente no he visto ningún patrón implementado en ejemplos de código que me guste. He analizado algunos de los proyectos de código abierto como KiGG, Oxite, codecampserver, etc ... pero ninguno de ellos realmente resuelve el problema de reducir mis Controladores. Me gustaría evitar pasar mucho HTTPContext, pero quizás esto no sea posible.

¿Hay algún otro proyecto, las mejores prácticas que podría estar mirando? Estoy construyendo una gran aplicación de flujo de trabajo/entrada de datos.

Gracias por algunos enlaces y sugerencias

Respuesta

3

No conozco ningún ejemplo real para presumir, porque creo que se me ocurrió el controlador de las aplicaciones MVC -> servicio -> esquema de capas de repositorio basado en preguntas aleatorias y respuestas que encontré por navegando SO.

Sin embargo, lo que puedo ofrecerle es un ejemplo de cómo organizar las viñetas que enumera en cómo encajarían en la forma en que he estructurado mi capa de servicio. Puede que esta no sea la mejor manera, pero así es como estoy haciendo mi aplicación de mvc a gran escala.Esto debería darle una idea de cómo estructurarlo en su propia aplicación

Mi capa de servicio combina una clase de servicio por unidad de negocio. Entonces, si mi aplicación tiene proyectos, y cada proyecto tiene una persona, tendría una clase ProjectService y una clase PersonService.

Según la descripción de cómo funcionan los controladores, las acciones de mi controlador funcionan de la siguiente manera.

1) Obtenga la información del usuario actual y llame al método de autorización de la clase de servicio apropiada. Entonces, si el usuario intenta modificar los detalles de un proyecto, pasaría la identificación del usuario y el ID del proyecto al método AuthorizeUser de ProjectService. Esto significa que si cambio la forma en que autorizo ​​a los usuarios para proyectos, solo tengo que cambiar el método de autorización y no todos los controladores.

2) Los modelos de vista se crean, guardan y destruyen en la capa de servicio. La capa de servicio toma el modelo de vista, lo valida (genera una excepción o resultado de validación si falla) y luego lo convierte en un objeto de datos, que luego pasará al repositorio para guardarlo. También solicita el objeto de datos del repositorio, lo convierte en un modelo de vista y lo devuelve al controlador.

3) El registro de todas las acciones ocurre en la capa de servicio. Esto puede ser automático en función de la acción que se presenta (intentar guardar un objeto en el archivo db) o su controlador puede llamar explícitamente a la capa de servicio para registrar la acción.

El objetivo de todo esto es consolidar la funcionalidad común en una capa fácil de mantener. Si cambia la forma en que su modelo de vista se convierte en DTO, es muy fácil saber dónde hacer el cambio y hacerlo una vez. Si necesita cambiar su registro, acceso de usuario o incluso si desea cambiar la forma de recuperar ciertos datos de los repositorios, es un área simple para cambiar en lugar de tener que buscar a todos sus controladores y modificarlos directamente.

Editar: Esto mantiene los controladores pequeños ya que solo contienen unas pocas llamadas a la capa de servicio y eso es todo (Autorizar, realizar acción, Mostrar vista). End Edit

Finalmente, el sitio web asp.net tiene un tutorial para realizar la validación en una capa de servicio. Ese tutorial se puede encontrar here.

+0

Estoy contemplando esta respuesta. Me gusta la idea de la autorización de clase de servicio. – taudep

+0

Acabo de ver el enlace que editó para agregar. Eso es realmente útil. Gracias por publicar eso. – taudep

+0

Con el artículo vinculado que ha enviado, están realizando llamadas AddModelError antiguas para su validación. Me pregunto si existe una manera de incorporar la validación más reciente de Anotaciones de datos. (Sin embargo, hay reglas de validación que escribo que no se asignan a los atributos.) – taudep

0

Aquí en mi empresa tenemos 5 proyectos en total:

  • Ver
  • controlador, en wich que sólo ponemos la lógica de los métodos de acción, y es ayudantes
  • lógica de negocios, donde ponemos la lógica específica para las operaciones, en su caso esto sería los ayudantes de los correos electrónicos, las validaciones de negocios, y donde llamaríamos a los repositorios para actualizar y crear objetos
  • Acceso a datos, donde colocamos los repositorios para consultas y operaciones de datos.
  • ORM, donde ponemos el modelo de base de datos, y las clases para el intercambio de datos entre cada capa

En este caso, todos los proyectos tienen una referencia al ORM, a continuación, la vista tiene una referencia al controlador, el controlador a la lógica de negocios y la lógica de negocios al acceso a datos.

+1

No veo cómo esto intenta responder a la pregunta, cómo evitar que los controladores exploten en tamaño. –

+0

Bueno, desde donde yo lo veo, poner algo de la lógica en otra capa reduciría el tamaño de los controladores. Crear una clase base para la mayoría de las operaciones comunes también ayudaría – Tejo

+0

Más detalles sobre esta capa de lógica de negocios de "otra capa", es lo que estoy buscando. Ejemplos de diseños, patrones, etc. ... – taudep

1

Me parece que confía en que su controlador juegue demasiados roles.

Al diseñar un controlador, normalmente lo considero como un control de acceso a un solo tipo de recurso. Esto quiere decir, por ejemplo, si estuviera creando esta página que está leyendo en este momento, donde puede publicar respuestas y comentarios, tendría 2 controladores, uno para respuestas y otro para comentarios. Evitaría agregar dos acciones a mi controlador de preguntas para el acceso a recursos no relacionados. Hay excepciones a esto, pero son pocas y distantes.

Además, la funcionalidad básica de cada controlador es que debe validar la entrada (incluso cuando se valida en el navegador porque cualquiera puede editar una solicitud), convertir la entrada en los objetos necesarios para pasar a la capa de servicio (o lógica comercial) y validar la respuesta de la capa de servicio antes de convertirla de nuevo en objetos utilizables por la vista y de devolverla al usuario. Todo lo demás debe manejarse en la capa de servicio, manteniendo el controlador delgado y predecible.

+0

Ummm ... sí, el controlador está haciendo mucho en cada acción. Todo lo que está haciendo, sin embargo, SÍ tiene que suceder con cada solicitud. Es por eso que estoy buscando ideas sobre cómo dividirlo mejor en servicios, etc. No estoy buscando dividir las diferentes acciones de un Controlador en múltiples acciones en un controlador, sino buscar romper una larga acción única métodos en mejores partes particionadas. – taudep

+0

Me doy cuenta de que esas cosas tienen que suceder en cada solicitud, pero no tienen que ser hechas por el controlador mismo. Por ejemplo, si la determinación de que el usuario debe enviarse por correo electrónico se basa en los datos devueltos por un repositorio, entonces quizás podría agregar una capa intermedia que pase la entrada al repositorio y realice la verificación antes de devolver los datos al controlador. Siempre que regule intencionalmente cada uno de sus objetos para un conjunto específico y constante de responsabilidades, dividir el trabajo generalmente fluye naturalmente. –

0

Bueno, algo de eso depende de lo que quiere decir con "el controlador es". Si usa anotaciones de datos para validar y filtros de acción para el registro, eso está perfectamente bien. No hay ninguna lógica en el controlador allí.¿Estás usando ViewModels y vistas fuertemente tipadas? Parece que el modelo con el que está trabajando su controlador ya debería ser el DTO simplificado, en lugar de tener la entidad completa y crear un DTO para enviar de vuelta. Tengo problemas para imaginar una situación en la que un controlador envíe un correo electrónico o verifique que se envió. Eso debería pasar a una capa de servicio. También miraría con dureza a un controlador que está operando en "objetos asociados". Probablemente debería estar llamando a un único método en el repositorio que maneja eso.

No he abierto Nerd Dinner, así que no puedo jurar lo que hay allí, pero ¿valdría la pena examinarlo?

+0

Sí, estoy usando ViewModels simplificados que modelan los datos en la interfaz de usuario. El problema es que los modelos de vista se dividen en múltiples objetos de datos para la persistencia. Hay muchas reglas complejas en este proceso, muchas verificaciones de autorización, etc. ... Creo que Nerd Dinner carece de las mejores prácticas decentes para una aplicación real. Después de todo, está basado en una base de datos con dos tablas. No trata con relaciones de muchos a muchos, o cualquier relación de datos compleja para ese asunto.A menudo tengo una lógica comercial que abarca 10 tablas en una única solicitud web. – taudep

Cuestiones relacionadas