Search code examples
c#dependency-injection.net-5

Circular reference in dependency injection


I am creating a RESTful api in Net 5, according to the instructions I must create repositories and services that make use of them. The logic must be in the services.

The Services I have are:

SubGroupService GroupsService

The problem I have is that I generated a circular reference since in GroupsService I need a method of SubGroupsService and SubGroupsService i need a method of GroupsService .

Injecting the GroupsService service into SubGroupsService there is no problem, but injecting SubGroupsService into GroupsService generates the circular reference.

Please can you tell me how to solve this type of problem, since I don't have much experience with dependency injection.

SubGroupService

public class SubGroupService: ISubGroupService
{       
    private readonly ISubGroupRepository _SubGroupRepository;
    private readonly IGroupService _GroupService;        
    public SubGroupService(
        ISubGroupRepository SubGroupRepository,
        IGroupService GroupService
    {          
        _SubGroupRepository = SubGroupRepository;
        _GroupService = GroupService;        
    }

    public async Task InsertSubGroupService(Subgroup subgroup)
    {
        var group = await _GroupService.GetGroupService(subgroup.idgroup);
        
        if (group != null)
        {
            await _SubGroupRepository.InsertSubGroupRepository(subgroup);
        }
        else
        {
            throw new BusinessException("This group not exists");
        }
    }

    public async Task<Subgroups> GetSubGroupService(int idgroup)
    {
        return await _SubGroupRepository.GetSubGroupRepository(idgroup);
    }
}

Group Service

public class GroupService : IGroupService
{
    private readonly ISubGroupService _SubGroupService;
    private readonly IGroupRepository _GroupRepository;
    public GroupService(
        ISubGroupService SubGroupService,
        IGroupRepository GroupRepository)
    {
        _SubGroupService = SubGroupService;
        _GroupRepository = GroupRepository;
    }

    public async Task<bool> DeleteGroupService(int Idgroup)
    {
        var existsSubGroup = await _SubGroupRepository(Idgroup);
        if(existsSubGroup == null)
        {
            return await _GroupRepository.DeleteGroupRepository(Idgroup);

        }
    }

    public async Task<Groups> GetGroupService(int Idgroup)
    {
        return await _GroupRepository.GetGroupRepository(Idgroup);
    }
}

Interfaces:

public interface IGroupService
{
    Task<Groups> GetGroupsService(int Idgroup);
    Task<bool> DeleteGroupService(int Idgroup);
}

public interface ISubGroupService
{
    Task<Subgroups> GetSubGroupService(int idsubgrupo);
    Task InsertSubgroupService(Subgroup subgroup);
}

Solution

  • You can't use constructor injection in that case. You can switch to property injection:

    public class SubGroupService: ISubGroupService
    {       
        private readonly ISubGroupRepository _SubGroupRepository;
        public IGroupService GroupService { get; set; }
        public SubGroupService(
            ISubGroupRepository SubGroupRepository)
        {          
            _SubGroupRepository = SubGroupRepository;
        }
    
        // methods of the class
    }
    
    public class GroupService : IGroupService
    {
        public ISubGroupService SubGroupService {get; set;}
        private readonly IGroupRepository _GroupRepository;
        public GroupService(
            IGroupRepository GroupRepository)
        {
            _GroupRepository = GroupRepository;
        }
        
        // methods of the class
    }
    

    You'll have to create the objects like this:

    IGroupRepository groupRepository = new GroupRepository();
    IGroupService groupService = new GroupService(groupRepository);
    ISubGroupService subGroupService = new SubGroupService(groupRepository);
    groupService.SubGroupSerivce = subGroupService;
    subGroupService.GroupService = groupService;
    

    Of course, creation of the objects is now much more complicated. You might put the creation into a facotry method to avoid errors:

    public (IGroupService,ISubGroupService) CreateGroupAndSubGroupService()
    {
       // code from above
    }
    

    And it is also advisable to add null checks, because someone might create the objects without initializing the service correctly.