Récemment, j'ai posé une question sur l'architecture logicielle
Le service doit-il appeler directement un autre service ou référentiel?
Après cette réponse, j'ai réorganisé et refactorisé ma candidature. D'une manière simple, mes services s'appellent les uns les autres, StudentService nécessite ClassService (par exemple pour obtenir le score moyen de la classe) et ClassService nécessite StudentService (pour obtenir des étudiants affectés à la classe). Les classes (simplifiées) sont présentées ci-dessous:
public class StudentService : IStudentService
{
protected readonly IClassService ClassService;
public StudentService(IClassService classService)
{
ClassService = classService;
}
}
public class ClassService : IClassService
{
protected readonly IStudentService StudentService;
public ClassService(IStudentService studentService)
{
StudentService = studentService;
}
}
Les services sont enregistrés dans le conteneur DI dans .NET Core
services.AddTransient<IStudentService, StudentService>();
services.AddTransient<IClassService, ClassService>();
Pendant la résolution
var studentService = app.ApplicationServices.GetService<IStudentService>();
J'obtiens une exception Une dépendance circulaire a été détectée pour le service de type ...
Je comprends le problème d'implémentation ici, mais je ne sais pas comment résoudre le problème d'architecture ici.
Pourriez-vous fournir une suggestion?
Edit: Ok, j'ai un cas plus réaliste, par exemple Employés, services et entreprises. Nous avons une couche de référentiel avec un référentiel CRUD générique abstrait. Ensuite, nous avons des classes dérivées: EmployeesRepository ServicesRepository et CompaniesRepository. EmployeesRepository implémente des méthodes: GetTopEmployeesOfTheMonth ServicesRepository implémente des méthodes: GetTopServicesForEmployees CompaniesRepository implémente des méthodes: GetCompaniesWithTopIncome
Sur la couche ci-dessus (appelons-la Business Layer), nous avons la même structure: abstrait générique CRUD Helper, par exemple vérifie les privilèges utilisateur et appelle les méthodes du référentiel CRUD. Ensuite, nous avons dérivé EmployeesHelper, ServicesHerlper et CompaniesHelper. Tous vérifient les privilèges des utilisateurs et appellent les méthodes du référentiel approprié (EmployeesHelper from EmployeesRepository, etc.). De plus, sur cette couche, nous avons des méthodes pour créer des objets plus "complexes" - les objets qui sont composés de nombreuses entités. Par exemple, CompaniesHelper a une méthode pour afficher les cinq premières entreprises avec les services les plus vendus. Les données seront affichées sur un écran, elles doivent donc être générées par une seule demande d'API et renvoyées en JSON. La méthode ShowCompaniesWithServices from CompaniesHelper appelle les méthodes CompaniesHelper et les méthodes EmployeesHelper. Sur le deuxième côté, nous avons EmployeesHelper, qui implémente une méthode pour renvoyer un objet complexe avec les meilleurs employés du mois, leurs meilleurs services et les entreprises qu'ils travaillent, il a donc besoin de Comapnies Helper.
Comment résoudre cette dépendance circulaire? Existe-t-il un modèle de conception pour le résoudre?
Donc, je ne pense pas que les services devraient avoir d'autres services injectés.
Je pense que chaque service devrait être autonome et fournir uniquement les données dont il est responsable. Le consommateur de IStudentService peut également être un consommateur de IClassService s'il a besoin de données des deux sources.
Je ne suis pas tout à fait sûr que la façon dont je l'ai fait est très propre, mais cela fonctionne très bien pour moi. Lorsque j'ai rencontré ce problème de dépendance circulaire, j'ai supprimé le service de l'injection de dépendance et j'ai simplement passé le service en tant que paramètre à la fonction qui en avait besoin.
Ainsi, lorsque vous appelez la méthode, cela ressemble à ceci:
// Inside the Student service
var result = _classService.GetClassStudents(classId, this)
Cela pourrait ne pas fonctionner pour tout le monde, mais dans mon cas, j'avais une configuration assez simple, donc je n'ai pas creusé plus profondément.
J'espère que cela t'aides.