3

I've been running into endless problems attempting to use Windsor with Web API and injecting HttpRequestMessage into downstream dependencies of a controller. Since I've tried all the matching answers on Stackoverflow, I'd like to ask the question in a different way:

In Castle Windsor, how can I resolve a component instance while supplying a value for a downstream dependency? That is, the supplied value is required by a component that is required by the component being resolved.

For context, I'm trying to inject HttpRequestMessage so that I can use it to resolve the request context (primarily to resolve an absolute URL).

Edit I'd also like to point out that I don't currently have a dependency on Web Host / System.Web and I'd rather not change that.

Richard Szalay
  • 83,269
  • 19
  • 178
  • 237
  • Can you post some code? Generally state doesn't get injected, so an abstract factory is used to resolve by value, or data is simply passed via a method (method injection). It sounds like what you're doing may be more complex? – Phil Sandler Jul 15 '14 at 03:22
  • Imagine `SomethingController` depends on `SomethingService`. `SomethingService` depends on `LinkGenerator`. `LinkGenerator` requires the current `HttpRequestMessage` so that it can generate an absolute URL. I need `HttpRequestMessage` to be regstered prior to creating each instance of `SomethingController` so that it will be available down at the `LinkGenerator` layer. – Richard Szalay Jul 15 '14 at 07:46

4 Answers4

0

A proper approach is to

  1. Create IMyDesiredRouteParameterProvider
  2. Implement it. Get the current request inside it and get the url
  3. Register it and inject it in the desired dependent class via constructor.

I made myself such an implementation and I can say that this way it works fine. You can make Web.Infrastructure assembly and put the implementation there. Or put both the interface and the implementation there if you are going to reference it from another web module.

using System;
using System.Web;

namespace RouteParameterProvider
{
    interface IMyRouteParameterProvider
    {
        string GetRouteParameter();
    }

    public class ControllerActionMethodRouteParameterProvider : IMyRouteParameterProvider
    {
        public string GetRouteParameter()
        {
            string Parameter = HttpContext.Current.Request.RequestContext.RouteData.Values["controller"] as string;
            if (string.IsNullOrEmpty(Parameter))
            {
                throw new InvalidOperationException();
            }
            return Parameter;
        }
    }
}

You can get every possible thing that the Request Context contains from :

HttpContext.Current.Request.RequestContext

And it will be better if you rethink your design decision :

I need HttpRequestMessage to be regstered prior to creating each instance of SomethingController so that it will be available down at the LinkGenerator layer.

Containers are to be initialized at runtime and then used to resolve.

Ognyan Dimitrov
  • 6,026
  • 1
  • 48
  • 70
  • `HttpContext` is only available on Web Host, which I cannot access. – Richard Szalay Jul 15 '14 at 23:02
  • Search around and dig deeper into the WEB API for such a solution and do not register-a-thing-per-web-call - this is a bad practice. Your problem is explained and solved [here](http://stackoverflow.com/questions/4343492/unity-application-block-how-pass-a-parameter-to-injection-factory) and in some articles pointed [here](http://stackoverflow.com/questions/11347807/httpselfhostserver-and-httpcontext-current) – Ognyan Dimitrov Jul 16 '14 at 07:13
  • I have dug deeper and been unsuccessful, hence my SO question. That question: 1) uses unity 2) calls a method on a service that is already registered. None of those things grant me access to resolve the bound endpoint of the web api application I'm hosted on. – Richard Szalay Jul 16 '14 at 07:34
0

I need HttpRequestMessage to be regstered prior to creating each instance of SomethingController so that it will be available down at the LinkGenerator layer.

It sounds like you want to register an item with the container at runtime, post-startup. In general, this is not a good practice--registration should be a discrete event that happens when the app is fired up, and the container's state should not be changed during runtime.

Dependency Injection is about resolving service components, not runtime state--state is generally passed via methods (method injection). In this case it sounds like your LinkGenerator component needs access to the ambient state of the request.

I'm not that familiar with HttpRequestMessage, but this answer seems to show that it is possible to retreive it from HttpContext.Current. You could make this a method on your LinkGenerator class, or wrap this call in a separate component that gets injected into LinkGenerator (HttpRequestMessageProvider?). The latter would be my preferred method, as it allows LinkGenerator to be more testable.

Community
  • 1
  • 1
Phil Sandler
  • 27,544
  • 21
  • 86
  • 147
  • If `LinkGenerator` used method injection, then `SomethingService` would also require method injection for the sole purpose of supplying it to `LinkGenerator`. That sounds like a leaky dependency to me. Also, that link has a dependency on WebHost / System.Web, which I'd rather not introduce. – Richard Szalay Jul 15 '14 at 23:03
  • Right--passing state via method injection two levels deep is a clear design smell. The second option is clearly the better one, but if that doesn't work, you may want to seriously consider if this is a problem that DI can effectively solve. In any case, I would strongly recommend against any solution that involves registering or re-registering at runtime. – Phil Sandler Jul 16 '14 at 14:02
0

Given the lack of a clean way of doing this and Web API not providing information as to the hosted endpoint beyond per-request context objects, I ended up injecting the base url from configuration.

Richard Szalay
  • 83,269
  • 19
  • 178
  • 237
0

Is this library by Mark Seemann the answer? In the description he writes explicitly :

This approach enables the use of Dependency Injection (DI) because the request can be injected into the services which require it.

Then gives an example :

// Inside an ApiController

var uri = this.Url.GetLink(a=> a.GetById(1337));

By which you can then pass the URL down the road in the service that you have injected in the controller.

UPDATE : Mark Seemann wrote about the same exact problem here:

"Because HttpRequestMessage provides the context you may need to compose dependency graphs, the best extensibility point is the extensibility point which provides an HttpRequestMessage every time a graph should be composed. This extensibility point is the IHttpControllerActivator interface:..."

This way you can pass request context information to a component deep in the object graph by getting from the HttpRequestMessage and passing it to the DI container. Just take a look at the interface of IHttpControllerActivator.

The WEB API framework gets the IHttpControllerActivator through DependencyResolver. You probably already replaced it by your CastleWindsorDependencyResolver. Now you have to implement and register your HttpControllerActivator and register it.

When the WEB API framework gets IHttpControllerActivator from DependencyResolver (your Castle Windsor DR) and calls IHttpControllerActivator.Create() it will pass you the HttpRequestMessage. You can get your info from there and pass it to the your CastleDR before you call Resolve(typeof(MyController)) which will resolve the whole object graph - that means you will have MyHttpContextInfo to inject in your XYZComponent deep in the resolution stack.

This way tou are passing the arguments in the last possible moment but it is still possible. In Castle Windsor I make such passing of arguments though CreationContext.AdditionalArguments["myArgument"];.

Community
  • 1
  • 1
Ognyan Dimitrov
  • 6,026
  • 1
  • 48
  • 70