¿Creando una capa de servicio para mi aplicación MVC?


82

Por lo que entiendo, MVC separa las definiciones de clase (modelo) de la presentación (vista) a través del "pegamento" que es el controlador. El responsable del tratamiento debe tener una única responsabilidad y, por tanto, ser comprobable. Los ViewModels se utilizan para reunir datos de varias entidades y para "masajear" los datos del controlador para la vista.

Parece que la lógica empresarial realmente no tiene cabida ... así que creo que otra capa de servicios sería adecuada. Simplemente no estoy seguro de dónde colocar esta capa, o cómo construir los servicios. ¿Debería ser una clase llamada "servicios" que contenga un montón de funciones? Soy un poco nuevo en MVC, por lo que cualquier material de lectura, muestras o consejos generales para recién llegados sería increíble.

Respuestas:


126

Normalmente uso una capa de servicio cuando desarrollo la aplicación ASP.NET MVC. Es similar al patrón de capa de servicio que Martin Fowler analiza en Patrones de arquitectura de aplicaciones empresariales . Encapsula su lógica empresarial y hace que los controladores sean bastante delgados. Básicamente, los controladores usan la capa de servicio para obtener los modelos de dominio que luego se transforman en modelos de vista. También utilizo el Patrón de diseño de unidad de trabajo para manejar transacciones y el Patrón de diseño de repositorio para encapsular la capa de acceso a datos para facilitar las pruebas unitarias y poder intercambiar fácilmente los ORM. Esta figura muestra las capas típicas que uso en una aplicación MVC.

Arquitectura MVC

La capa de servicio está etiquetada como "Capa de aplicación o dominio" en este diagrama porque encuentro que la gente se confunde cuando se usa el término "Capa de servicio". Suelen pensar que se trata de un servicio web. En realidad, es un ensamblado que puede utilizar su tecnología de servicio web favorita, como ASP.NET Web API o WCF, así como un controlador.

En cuanto a las convenciones de nomenclatura, suelo utilizar algo que describa el dominio seguido del servicio. Por ejemplo, si tengo una capa de servicio que maneja la membresía del usuario, entonces tendría una clase llamada MembershipService que tiene todos los métodos que necesitan los controladores y los servicios web para consultar y manipular el dominio de membresía. Tenga en cuenta que puede tener varios dominios en la misma aplicación, por lo que puede tener varias capas de servicio. Mi punto aquí es que no es necesario tener un servicio monolítico que se encargue de toda la aplicación.


7
¿Existe un buen ejemplo que implemente esta metodología?
Animesh

@Animesh solo tiene que componer con ejemplos en la red, EF + Code First o plantilla POCO para DAL, T4Scaffolding para generar Repository y UnitOfWork, Service es solo coordinación entre DAL y POCO encapsulando la lógica empresarial. Luego ASP.NET MVC Controller O WebApi que solo llama a la capa de servicio y muestra resultados (ASP.NET MVC) o lo expone a otro cliente (ASP.NET WebApi)
riadh gomri

2
El repositorio y UoW son innecesarios, ¿no? Al menos en su ejemplo, cuando tiene que usar solo una tecnología de base de datos (y no es DDD). Es por eso que EF ya ha implementado UoW y los patrones de repositorio.
krypru

1
No sé de aquí, ya que me gusta el ejemplo y el gráfico, pero muchos tutoriales en línea usan el patrón de repositorio innecesariamente. Se abstraen porque pueden abstraer sin ningún beneficio, solo para poder usar una interfaz.
johnny

Increíble !!! Gracias @kevin Junghans, su respuesta realmente me ayudó a diseñar una aplicación web compleja. Una breve pregunta, mientras desarrollamos aplicaciones web basadas en microservicios, ¿necesitamos implementar clases de servicio o simplemente las clases MVC hacen el trabajo?
codemilan

28

Mi consejo es crear clases separadas llamadas "servicios". Colóquelos en un proyecto de biblioteca de clases diferente (o espacio de nombres) y hágalos independientes de la infraestructura del marco MVC. Recomiendo usar también algún tipo de inyección de dependencia (la mejor es la inyección de constructor). Entonces sus clases de servicio pueden verse así:

 public class MyService : IMyService
 {
     IFirstDependency _firstService;
     ISecondDependency _secondService;

     public MyService(IFirstDependency firstService, ISecondDependency secondService)
     {
     }

     public Result DoStuf(InputDTO)
     {
         // some important logic         
     }
 }

Entonces consumes estos servicios de tus controladores. Mira aquí para ver un ejemplo completo.

De acuerdo con los repositorios, mi consejo es que no los use si va a usar algún ORM moderno (NHibernate, EntityFramework), porque su lógica comercial estará encapsulada en la capa de servicio y su base de datos ya estará encapsulada con el marco ORM.


4
Creo que el problema de omitir la sección del repositorio e ir directamente al ORM es que sus clases de servicio obtendrán directamente el contexto ORM, lo que significa que todas esas clases en su servicio tendrán acceso a todas las tablas que sacó del contexto en lugar de cada servicio. clase trabajando solo con las tablas que necesita. Puede evitar esto pasando DbSet al ctor de cada clase y resolviéndolo con DI, pero ¿puede tener problemas con eso?
user441521


10

¿Citando "La lógica empresarial debería estar en un servicio, no en un modelo"? :

En una arquitectura MVP / MVC / MVVM / MV *, los servicios no existen en absoluto. O si lo hacen, el término se usa para referirse a cualquier objeto genérico que pueda inyectarse en un controlador o modelo de vista. La lógica empresarial está en su modelo. Si desea crear "objetos de servicio" para orquestar operaciones complicadas, eso se ve como un detalle de implementación. Mucha gente, lamentablemente, implementa MVC de esta manera, pero se considera un anti-patrón (Modelo de dominio anémico) porque el modelo en sí no hace nada, es solo un montón de propiedades para la interfaz de usuario.

Algunas personas piensan erróneamente que tomar un método de controlador de 100 líneas y meterlo todo en un servicio de alguna manera mejora la arquitectura. Realmente no lo hace; todo lo que hace es agregar otra capa de indirección, probablemente innecesaria. Hablando en términos prácticos, el controlador todavía está haciendo el trabajo, simplemente lo está haciendo a través de un objeto "auxiliar" mal llamado. Recomiendo encarecidamente la presentación Wicked Domain Models de Jimmy Bogard como un ejemplo claro de cómo convertir un modelo de dominio anémico en uno útil. Implica un examen cuidadoso de los modelos que está exponiendo y qué operaciones son realmente válidas en un contexto empresarial.


Esta es la mejor respuesta. El seleccionado dice poner lógica empresarial en los servicios que se utilizarán en el controlador, pero la lógica empresarial debería estar en el modelo.
Mateus Felipe

3

Parece que estarías buscando algo como un patrón de repositorio. Usted puede leer sobre ello aquí:

http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net- aplicación-mvc

Esta respuesta aquí también puede ayudar:

El mejor patrón de repositorio para ASP.NET MVC


4
Es mucho más que el patrón de repositorio. Los servicios están a punto de acceso a datos demasiado , pero no exclusivamente, en mi humilde opinión.
boj
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.