AmirHosseinMp02
AmirHosseinMp02

Reputation: 77

Error while validating the service descriptor: A circular dependency was detected

I have two classes, AccountService:

public class AccountService : IAccountService
{
    private readonly UserManager<CustomIdentityUser> _userManager;
    private readonly SignInManager<CustomIdentityUser> _signInManager;
    private readonly RoleManager<CustomIdentityRole> _roleManager;
    private readonly IUserRepository _userRepository;
    private readonly LinkGenerator _linkGenerator;
    private readonly IHttpContextAccessor _accessor;
    private readonly IMediaService _mediaService;

    public AccountService(
        UserManager<CustomIdentityUser> userManager,
        SignInManager<CustomIdentityUser> signInManager,
        LinkGenerator linkGenerator,
        IHttpContextAccessor accessor,
        IMediaService mediaService,
        RoleManager<CustomIdentityRole> roleManager,
        IUserRepository userRepository)
    {
        _userManager = userManager;
        _signInManager = signInManager;
        _linkGenerator = linkGenerator;
        _accessor = accessor;
        _mediaService = mediaService;
        _roleManager = roleManager;
        _userRepository = userRepository;
    }

and the other called MediaService:

public class MediaService : IMediaService
{
    private readonly IMediaRepository _mediaRepository;
    private readonly IAccountService _accountService;
    private readonly IHttpContextAccessor _accessor;

    public MediaService(
        IMediaRepository mediaRepository,
        IAccountService accountService,
        IHttpContextAccessor accessor)
    {
        _mediaRepository = mediaRepository;
        _accountService = accountService;
        _accessor = accessor;
    }
}

I injected these two into the IoC layer to use:

services.AddScoped<IMediaService, MediaService>();
services.AddScoped<IAccountService, AccountService>();

But I get an error at runtime:

Error while validating the service descriptor 'ServiceType: Aroma_Shop.Application.Interfaces.IMediaService Lifetime: Scoped ImplementationType: Aroma_Shop.Application.Services.MediaService': A circular dependency was detected for the service of type 'Aroma_Shop.Application.Interfaces.IMediaService'.

Aroma_Shop.Application.Interfaces.IMediaService(Aroma_Shop.Application.Services.MediaService) -> Aroma_Shop.Application.Interfaces.IAccountService(Aroma_Shop.Application.Services.AccountService) -> Aroma_Shop.Application.Interfaces.IMediaService"}

I understand where the problem is, if you look at the two classes AccountService and MediaService, you will notice that within each of these two classes, I requested to inject the other class. In AccountService I requested from service to inject MediaService, and in MediaService I requested from service to inject AccountService

The service descriptor can't inject these two classes, because when it wants to inject AccountService, it needs a MediaService to generate an object from it, and when it wants to inject MediaService, it needs AccountService to generate an object from it.

If possible, please help me solve this problem. Thanks a lot.

Upvotes: 1

Views: 1334

Answers (3)

MindingData
MindingData

Reputation: 12460

Put simply, you cannot have two classes requiring DI that injects each other, it's a little bit of a chicken and egg scenario.

As some other answers have mentioned, you can use a ServiceLocator pattern, but this is not advisable and is actually just a bandaid that hides the real issue.

The only way to solve this is to remove one of the dependencies. Without seeing what methods each are calling, I think it makes more sense to have AccountService dependant on the MediaService.

So with that said, whatever MediaService is calling inside AccountService, I would create a new service that satisfies that for both services. Let's say MediaService calls the AccountService to find the CurrentLoggedInAccount. I would create an ICurrentAccountService, and move the relevant method from the AccountService to this service. Then have AccountService and MediaService depend on this service.

No matter what, you have to refactor your code. It cannot be solved with a one line fix.

More info : https://dotnetcoretutorials.com/2020/09/14/dealing-with-circular-dependency-injection-references/

Upvotes: 0

Guru Stron
Guru Stron

Reputation: 141845

You can also register factory to resolve the dependency. Some containers provide build in Func "factories" for registered services but with Microsoft's one you can do as simple as:

services.AddScoped<Func<IMediaService>>(c => c.GetRequiredService<IMediaService>);

And resolve Func<IMediaService> instead of IMediaService in AccountService:

public AccountService(... Func<IMediaService> mediaServiceFactory,...)
{
    ...
    _mediaService = mediaServiceFactory(); (or in place where it is called)
    ...
}

Also note that if you have some recursive call path you are just deferring it till the runtime, so in case of infinite recursion you end up with StackOverflow exception, so maybe it is worth of effort to some move parts of the reused functionality to another class to prevent such circular dependencies.

Upvotes: 0

David Browne - Microsoft
David Browne - Microsoft

Reputation: 89006

Or if they are so interdependent, you can provide a single implementation for both services, eg

AccountAndMediaService : IAccountService, IMediaService

Upvotes: 1

Related Questions