Ce n’est pas une mauvaise pratique pour un contrôleur d’appeler directement un référentiel. Un "service" n'est qu'un autre outil, utilisez-le lorsque cela vous semble utile.
NikolaiDante a commenté:
... Choisissez le bon motif pour la bonne application. Ce que je dirais, c'est que vous devriez rendre votre demande cohérente.
Je ne pense pas que la cohérence soit l'aspect le plus important. Une classe "service" est destinée à encapsuler une logique de niveau supérieur afin que le contrôleur n'ait pas besoin de l'implémenter. S'il n'y a pas de "logique de niveau supérieur" requise pour une opération donnée, il suffit d'aller directement au référentiel.
Pour promouvoir une séparation et une testabilité correctes, le référentiel doit être une dépendance que vous injectez dans le service via un constructeur:
IFooRepository repository = new FooRepository();
FooService service = new FooService(repository);
service.DoSomething(...);
Si la recherche d'enregistrements dans la base de données nécessite une sorte de requête paramétrée, une classe de service peut être un bon endroit pour intégrer votre modèle de vue et créer une requête qui est ensuite exécutée par le référentiel.
De même, si vous avez un modèle de vue complexe pour un formulaire, une classe de service peut encapsuler la logique de création, de mise à jour et de suppression d'enregistrements en appelant des méthodes sur vos modèles de domaine / entités, puis en les conservant à l'aide d'un référentiel.
Si votre contrôleur doit obtenir un enregistrement par son ID, déléguer à un objet de service à cet effet revient à frapper une punaise avec une masse, c'est bien plus que ce dont vous avez besoin.
J'ai constaté que le contrôleur est le mieux placé pour gérer la transaction, ou un objet Unit of Work . Le contrôleur ou l'objet Unité de travail déléguerait ensuite des objets de service pour des opérations complexes ou irait directement au référentiel pour des opérations simples (comme la recherche d'un enregistrement par identifiant).
public class ShoppingCartsController : Controller
{
[HttpPost]
public ActionResult Edit(int id, ShoppingCartForm model)
{
// Controller initiates a database session and transaction
using (IStoreContext store = new StoreContext())
{
// Controller goes directly to a repository to find a record by Id
ShoppingCart cart = store.ShoppingCarts.Find(id);
// Controller creates the service, and passes the repository and/or
// the current transaction
ShoppingCartService service = new ShoppingCartService(store.ShoppingCarts);
if (cart == null)
return HttpNotFound();
if (ModelState.IsValid)
{
// Controller delegates to a service object to manipulate the
// Domain Model (ShoppingCart)
service.UpdateShoppingCart(model, cart);
// Controller decides to commit changes
store.SaveChanges();
return RedirectToAction("Index", "Home");
}
else
{
return View(model);
}
}
}
}
Je pense qu’une combinaison de services et de travailler directement avec des dépôts est parfaitement acceptable. Vous pouvez en outre encapsuler la transaction dans un objet Unit of Work si vous en ressentez le besoin.
La répartition des responsabilités est la suivante:
- Le contrôleur contrôle le flux de l'application
- Renvoie "404 non trouvé" si le panier n'est pas dans la base de données.
- Re-rend le formulaire avec des messages de validation si la validation échoue
- Enregistre le panier si tout est vérifié
- Le contrôleur délègue à une classe de service l'exécution de la logique applicative sur vos modèles de domaine (ou entités). Les objets de service ne doivent pas implémenter de logique métier! Ils exécutent la logique métier.
- Les contrôleurs peuvent déléguer directement aux référentiels pour des opérations simples
- Les objets de service prennent des données dans le modèle de vue et les délèguent à des modèles de domaine pour exécuter une logique métier (par exemple, les méthodes d'appels de service appellent les modèles de domaine avant d'appeler des méthodes sur le référentiel).
- Les objets de service sont délégués aux référentiels pour la persistance des données
- Les contrôleurs doivent soit:
- Gérer la durée de vie d'une transaction, ou
- Créer un objet Unité de travail pour gérer la durée de vie d'une transaction