I am trying to inject a collection of implementations of IResourceService into another implementation of IResourceService so that the first implementation is able to redirect to the correct service in the case where it can't operate on the resource. Every implementation of this I have tried so far has lead to a Cyclic Dependency - so I either want to know how to work around this or how to design this so that it isn't a problem.
I'm creating a number of controllers that all look after different resources. I'll simplify for the case of this question - but in effect I have a PetController that is able to do simple operations on pets which are all provided Ids. So for example navigating to /pet/1234 will give you a summary of the pet's details and what type of pet it is.
I then have a number of controllers for each pet type I.e. DogController, CatController and HamsterController. All of these inherit from a BasePetController which is actually doing all of the heavy lifting. In the scenario where you perform an operation on /dog/1234 but PetId 1234 actually corresponds to a Hamster, I want the DogController to return an appropriate response (Redirect on a Get, Confict on an update etc).
So I have something like this:
BasePetController : IResourceController
{
BasePetController(IResourceController[] resourceControllers){}
abstract Type SupportedResourceType { get; }
}
DogController : BasePetController
{
DogController(IResourceController[] resourceControllers) : base(resourceControllers) {}
Type SupportedResourceType => typeof(Dog);
}
This is then added to DI like so:
services.AddSingleton<IResourceController, DogController>();
services.AddSingleton<IResourceController, CatController>(); // etc.
This leads to a cyclic dependency because the DogController needs itself in order to create itself effectively.
I have tried to inject a ResourceControllerSelector to separate out this conflict a little further but no dice.
What I want is for the controller to go (In Pseudo Code)
If (can't update dog because it isn't a dog) {
controller = getResourceControllerForPet()
action = controller.GetActionForUpdateOperation()
return information for the user to go to the correct action
}
I think the individual pet controllers should be responsible for knowing whether or not that can handle a specific resource - rather than another service knowing all of this information + which actions to call etc. But can't figure out how to give each pet controller the ability to go and get this information themselves and/or in the API layer without creating a cyclic dependency.
Any help on this would be much appreciated. Whether its help with the dependency injection problem, or the design of the services required or even the API itself.
Adding implementation of the ResourceControllerSelector where resourceControllers is an IEnumerable<IResourceController>.
public IResourceController SelectController(Type resourceType)
{
EnsureArg.IsNotNull(resourceType, nameof(resourceType));
return this.resourceControllers.SingleOrDefault(x => x.SupportedResourceType == resourceType)
?? throw new ArgumentOutOfRangeException(nameof(resourceType), resourceType, "No resource controller has been configured to handle the provided resource.");
}
ResourceControllerSelectoras that seems about right to me. If asking for an instance ofIResourceControllerI'd expect only one type to be resolved.ResourceControllerSelectordoes seem like the right way to go if you don't change how the code is structured. Unfortunately since we don't know your problem domain, we can't really help with that.ResourceControllerSelectorinto the controllers, but also the controllers into theResourceControllerSelector