Resolving HttpControllerContext with Castle Windsor

雨燕双飞 提交于 2019-11-27 13:30:33

It seems to me that your InlineDependenciesPropagatingDependencyResolver is actually masking something fairly critical to the architecture of your application: that one or more of your components have dependencies that cannot be reliably resolved statically, from the container, or from dynamic context.

It violates the assumption most developers would make when passing inline dependencies to Resolve() (that they only get passed down one level of dependency resolution) and in certain scenarios could cause a dependency to incorrectly override some other configured service. (E.g. if you had another component many levels down which had a dependency of the same type and name). It could be a potential cause of bugs that would be very difficult to identify.

The issue at the heart of this is a difficult one for DI and really indicates that IoC is not really feasible (i.e. our dependency(ies) need to be 'pushed' and cannot be 'pulled' for us by the container). It seems to me there are two options:

1) rectify the problem that is preventing 'inversion'. i.e. wrap the HttpControllerContext/HttpContext, augment that wrapper to behave as required in a self-hosted scenario and have your components rely on that wrapper, rather than HttpControllerContext/HttpContext directly.

2) reflect the shortcomings of the environment you are working with (that it doesn't fully support 'inversion') and make the workaround to handle those shortcomings very explicit. In your scenario this would probably involve utilising a typed factory (interface) to instantiate the component requiring a baseUri in your IHttpControllerActivator.Create(). This would mean that if this component was further down the dependency hierarchy, you would need to explicitly build up your dependency hierarchy until you had your controller.

I would probably go for the second option simply because when conventions don't cut it I prefer to be as explicit as possible.

UPDATED Assuming we had a controller type A, which relied on component B, which in turn relied on the baseUri, the second option might look something like:

// Typed factories for components that have dependencies, which cannot be resolved statically
IBFactory bFactory; 
IAFactory aFactory;

public IHttpController Create(HttpControllerContext controllerContext, Type controllerType)
{
    if (controllerType == typeof(A))
    {
        // Special handling for controller where one or more dependencies
        // are only available via controllerContext.
        var baseUri = new Uri(controllerContext.Request.RequestUri.GetLeftPart(UriPartial.Authority));
        B b = this.bFactory.Create(baseUri);
        return this.aFactory.Create(b);
    }
    // Default for all other controllers 
    return (IHttpController)this.container.Resolve(controllerType);
}

The key points are that this explicitly deals with the shortcomings of our environment, it binds the affected types specifically with the dependency overrides we provide imperatively and ensures that we are not accidentally overriding any other dependencies.

Just for the sake of completeness, an answer I got from Krzysztof Koźmic (the current maintainer of Castle Windsor) on Twitter indicated that the method outlined in the question is, indeed, the correct way of achieving this particular goal.

(However, I can't link to that tweet, since Krzysztof's twitter account is protected (tweets are not publicly visible.))

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!