I've tried following advice from existing posts to make HttpRequestMessage
available as a constructor dependency for services in Web API:
ASP Web Api - IoC - Resolve HttpRequestMessage
Resolving HttpControllerContext with Castle Windsor
This advice works fine if all the dependencies only have one constructor. But when a dependency has multiple constructors, dependency resolution fails.
Any ideas how to extend the idea to work with multiple constructors?
=======================
The existing approach is summarised as follows:
First you add the HttpRequestMessage
as an additional named argument when resolving the controller in your IHttpControllerActivator
:
public IHttpController Create(
HttpRequestMessage request,
HttpControllerDescriptor controllerDescriptor,
Type controllerType)
{
var controller = (IHttpController)container.Resolve(
controllerType,
new { request });
Then you propagate this argument in the CreationContext
:
public class InlineDependenciesPropagatingDependencyResolver :
DefaultDependencyResolver
{
protected override CreationContext RebuildContextForParameter(
CreationContext current,
Type parameterType)
{
if (parameterType.ContainsGenericParameters)
{
return current;
}
return new CreationContext(parameterType, current, true);
}
}
This works fine when all the dependencies only have one constructor.
In my case, I have a hierarchy of dependencies:
- The controller depends on
IServiceA
ServiceA
depends onIServiceB
ServiceB
depends onIServiceC
ServiceC
depends onHttpRequestMessage
Where ServiceC
looks like this:
public class ServiceC: IServiceC
{
private readonly HttpRequestMessage request;
public ServiceC(HttpRequestMessage request)
{
this.request = request;
}
And ServiceB
has two constructors:
public class ServiceB: IServiceB
{
public ServiceB(string paramForTests)
{
// Do stuff
}
public ServiceB(IServiceC serviceC)
{
// Do stuff
}
But then Windsor fails to resolve ServiceC
.
The problem seems to be in the SelectEligibleConstructor
logic of DefaultComponentActivator. It calls into the CanResolve
method in DefaultDependencyResolver which eventually ends up at:
protected virtual bool CanResolveFromKernel(CreationContext context, ComponentModel model, DependencyModel dependency)
{
if (dependency.ReferencedComponentName != null)
{
// User wants to override
return HasComponentInValidState(dependency.ReferencedComponentName, dependency, context);
}
if (dependency.Parameter != null)
{
return true;
}
if (typeof(IKernel).IsAssignableFrom(dependency.TargetItemType))
{
return true;
}
if (dependency.TargetItemType.IsPrimitiveType())
{
return false;
}
return HasAnyComponentInValidState(dependency.TargetItemType, dependency, context);
}
And then HasAnyComponentInValidState
just looks at whether ServiceC
has already been resolved, it doesn't actually check whether it can be resolved.
If there is only one constructor, then the code calls the Resolve
methods, which correctly recursively resolve the dependencies, and ServiceC is available ok.
I don't want to limit my services to only having one constructor (or use the [DoNotSelect]
attribute to only leave one for Castle to look at).
Any ideas how to inject arguments as I have done, and still have it work with multiple constructors?