75 votes

Création d'une couche de services pour mon application MVC?

De ce que je comprends, le MCV sépare les définitions de classes (modèle) de la présentation (vue) via le "lien" qu'est le contrôleur. Le contrôleur devrait avoir une seule responsabilité et donc être testable. Les ViewModels sont utilisés pour rassembler des données provenant de plusieurs entités et pour "masser" les données du contrôleur pour la vue.

Il semble que la logique métier n'a pas vraiment sa place... donc je pense qu'une autre couche de services serait appropriée. Je ne suis tout simplement pas sûr de où placer cette couche, ou comment construire les services - devrait-il s'agir d'une classe appelée "services" contenant un tas de fonctions? Je suis un peu nouveau en MVC, donc tout matériel de lecture, exemples, ou des conseils pour débutants seraient géniaux.

119voto

Kevin Junghans Points 10012

Je utilise généralement un Service Layer lors du développement d'une application ASP.NET MVC. Il est similaire au Service Layer Pattern dont Martin Fowler parle dans Patterns of Enterprise Application Architecture. Il encapsule la logique métier et rend les contrôleurs assez minces. Fondamentalement, les contrôleurs utilisent la couche de service pour obtenir les modèles de domaine qui sont ensuite transformés en modèles de vue. J'utilise également le Unit of Work Design Pattern pour gérer les transactions et le Repository Design Pattern pour encapsuler la couche d'accès aux données afin de faciliter les tests unitaires et de pouvoir facilement remplacer les ORM. Cette figure montre les couches typiques que j'utilise dans une application MVC.

Architecture MVC

La couche de service est désignée comme la "couche d'application ou de domaine" dans ce diagramme car je trouve que les gens sont confus lorsque vous utilisez le terme "Service Layer". Ils ont tendance à penser que c'est un service Web. En réalité, c'est une assemblée qui peut être utilisée par votre technologie de service Web préférée, telle que ASP.NET Web API ou WCF, ainsi que par un contrôleur.

En ce qui concerne les conventions de nommage, j'utilise généralement quelque chose qui décrit le domaine suivi de service. Par exemple, si j'ai une couche de service qui gère l'adhésion des utilisateurs, je aurais une classe appelée MembershipService qui contient toutes les méthodes nécessaires aux contrôleurs et services Web pour interroger et manipuler le domaine de l'adhésion. Notez que vous pouvez avoir plusieurs domaines dans la même application, vous pouvez donc avoir plusieurs couches de service. Mon point ici est que vous n'avez pas nécessairement à avoir un service monolithique qui gère toute l'application.

26voto

MajoB Points 3778

Mon conseil est de créer des classes séparées appelées "services". Mettez-les dans un projet de bibliothèque de classes (ou un espace de noms) différent et rendez-les indépendants de l'infrastructure du framework MVC. Je recommande également d'utiliser une forme d'injection de dépendances (la meilleure étant l'injection par constructeur). Ensuite, vos classes de service peuvent ressembler à ceci :

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

    public MyService(IFirstDependency firstService, ISecondDependency secondService)
    {
    }

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

Ensuite, vous consommez ces services depuis vos contrôleurs. Consultez ici pour un exemple complet.

En ce qui concerne les Repositories - mon conseil est de ne pas les utiliser si vous avez l'intention d'utiliser un ORM moderne (NHibernate, EntityFramework), car votre logique métier sera encapsulée dans la couche de service et votre base de données sera déjà encapsulée avec le framework ORM.

13voto

Arvand Points 157

Citer de "La logique métier devrait être dans un service, pas dans un modèle"?:

Dans une architecture MVP/MVC/MVVM/MV*, les services n'existent pas du tout. Ou s'ils existent, le terme est utilisé pour se référer à n'importe quel objet générique qui peut être injecté dans un contrôleur ou un modèle de vue. La logique métier est dans votre modèle. Si vous voulez créer des "objets de service" pour orchestrer des opérations compliquées, cela est perçu comme un détail d'implémentation. Beaucoup de gens, malheureusement, implémentent le MVC de cette manière, mais c'est considéré comme un anti-pattern (Modèle de Domaine Anémique) car le modèle en lui-même ne fait rien, c'est juste un ensemble de propriétés pour l'interface utilisateur.

Certaines personnes pensent à tort que prendre une méthode de contrôleur de 100 lignes et tout mettre dans un service améliore d'une manière ou d'une autre l'architecture. En réalité, cela ne fait pas vraiment; tout ce qu'il fait, c'est ajouter une autre couche d'indirection, probablement inutile. En pratique, le contrôleur réalise toujours le travail, mais le fait à travers un objet "helper" mal nommé. Je recommande vivement la présentation de Jimmy Bogard sur Wicked Domain Models pour un exemple clair de comment transformer un modèle de domaine anémique en un modèle utile. Cela implique un examen attentif des modèles que vous exposez et quelles opérations sont réellement valides dans un contexte métier.

10voto

emre nevayeshirazi Points 6245

Jetez un œil à l'article sur les meilleures pratiques de MSDN.

Le code source de l'application dans l'article peut être trouvé ici.

3voto

malik Points 4842

Il semble que vous recherchiez quelque chose comme un motif de dépôt. Vous pouvez en apprendre davantage ici:

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

Cette réponse ici pourrait également vous aider:

Meilleur motif de dépôt pour ASP.NET MVC

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X