最近我问了一个有关软件体系结构的问题
Should service call another service or repository directly?
在回答之后,我对应用程序进行了重组和重构。用一种简单的方式,我的服务彼此调用,StudentService需要ClassService(例如,获取平均课程分数),ClassService需要StudentService(,以将学生分配给班级)。下面显示了类(简化的):
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;
}
}
服务在.NET Core的DI容器中注册
services.AddTransient<IStudentService, StudentService>();
services.AddTransient<IClassService, ClassService>();
解决过程中
var studentService = app.ApplicationServices.GetService<IStudentService>();
我得到一个异常。检测到类型为...的服务的循环依赖关系。
我在这里了解实现问题,但是在这里我不知道如何解决体系结构问题。
您能提供一些建议吗?
编辑: 好吧,我有更现实的案例,例如员工,服务和公司。 我们的存储库层带有抽象的通用CRUD存储库。 然后,我们派生了类:EmployeesRepository ServicesRepository和CompaniesRepository。 EmployeesRepository实现方法:GetTopEmployeesOfTheMonth ServicesRepository实现方法:GetTopServicesForEmployees CompaniesRepository实现方法:GetCompaniesWithTopIncome
在上面的层(我们称为业务层)上,我们具有相同的结构: 抽象的通用CRUD助手,例如检查用户权限并从CRUD存储库中调用方法。 然后,我们派生了EmployeesHelper,ServicesHerlper和CompaniesHelper。 它们全部检查用户权限并从适当的存储库(EmployeesRepository等的EmployeesHelper)中调用方法。 此外,在这一层上,我们具有创建更多“复杂”对象的方法,这些对象是由许多实体组成的对象。 例如,CompaniesHelper具有显示服务销售最多的前五家公司的方法。 数据将显示在一个屏幕上,因此应由一个API请求生成并作为JSON返回。 CompaniesHelper方法中的ShowCompaniesWithServices调用CompaniesHelper方法和EmployeesHelper方法。 在第二面,我们有EmployeesHelper,它实现了方法以返回当月最高雇员的复杂对象, 他们的顶级服务和所工作的公司,因此需要Comapnies Helper。
如何解决这种循环依赖关系?是否有解决的设计模式?
答案 0 :(得分:1)
因此,我认为服务不应注入其他服务。
我认为每个服务应该能够独立存在并仅提供其负责的数据。如果IStudentService的使用者也需要来自两个来源的数据,则也可以是IClassService的使用者。
答案 1 :(得分:0)
您有两种方法:
编写代码,从而无需从StudentService调用ClassService(或从ClassService调用StudentService)
创建第三类:
public class StudentService: IStudentService
{
private readonly IClassSharedSerive _classSharedService;
...
}
public class ClassService: IClassService
{
private readonly IClassSharedSerive _classSharedService;
private readonly IStudentService _studentService;
...
}
public class ClassSharedService: IClassSharesService
{
... without references to IClassService and IStudentService
}
但是,在大多数情况下,需要正确编写StudentService和ClassService(方法1)
答案 2 :(得分:0)
我不能完全确定我解决此问题的方法是否很干净,但是对我来说效果很好。当遇到循环依赖问题时,我从“依赖注入”中删除了该服务,只是将该服务作为参数传递给需要它的函数。
因此,当您调用该方法时,它看起来像这样:
// Inside the Student service
var result = _classService.GetClassStudents(classId, this)
可能不适用于每个人,但就我而言,我的设置非常简单,因此我没有深入研究。
希望这会有所帮助。