ASP.NET MVC & Windsor.Castle: working with HttpContext-dependent services

I have several dependency injection services which are dependent on stuff like HTTP context. Right now I’m configuring them as singletons the Windsor container in the Application_Start handler, which is obviously a problem for such services.

What is the best way to handle this? I’m considering making them transient and then releasing them after each HTTP request. But what is the best way/place to inject the HTTP context into them? Controller factory or somewhere else?

alexandrul
3,27021436
asked Nov 30 ’09 at 10:01
Igor Brejc
4,9521330
74% accept rate

2 Answers

With Castle Windsor you can use the PerWebRequest lifetime – that should fit pretty well with your requirements.

That means you can just inject the HTTP stuff into your services, and the container will take care of the proper lifetime management. However, this requires you to also register all these services (and all consumers of those services and so on) as PerWebRequest (or Transient) because if you register them as Singletons, they will hold on to stale (and possibly disposed) contexts.

answered Nov 30 ’09 at 11:33
Mark Seemann
36.1k32470
Mark, thanks for the info – I didn’t know about PerWebRequest. I’ll check it out. – Igor Brejc Nov 30 ’09 at 12:02
Mark, I’ve looked into PerWebRequest, but I still don’t see how services can obtain HttpContext. When I try to register an instance of HttpContextBase it in the container myself, it fails after the second request (since an instance was already registered in the previous request). I couldn’t find anything on Google so far… – Igor Brejc Nov 30 ’09 at 12:58
I may have misunderstood what you are trying to do, but you can’t use the HttpContext from Application_Start because at this point there is no HttpContext (PerWebRequest or no PerWebRequest). Now that I think about it, it makes no sense to attempt to control the lifetime of the HttpContext from the DI Container, since this lifetime is already being managed by the ASP.NET MVC framework. What you can do is to hook into a custom IControllerFactory and grab the HttpContext served to you at that point, and then use a factory method to wire up everything else that depends on it. – Mark Seemann Nov 30 ’09 at 14:12
Mark: a colleague of mine suggested accessing HttpContext.Current property, without injection or factory methods. It’s not very DI-friendly, but it looks like it works. I’ve registered these services as PerWebRequest, just to be on the safe side. – Igor Brejc Nov 30 ’09 at 14:49

Just like Mark said, you need to register these http-dependent services either as PerWebRequest or Transient. Here’s a sample that shows how to register and inject a HttpRequest or HttpContext:

public class Service {
    private readonly HttpRequestBase request;

    public Service(HttpRequestBase request) {
        this.request = request;
    }

    public string RawUrl {
        get {
            return request.RawUrl;
        }
    }
}

...

protected void Application_Start(object sender, EventArgs e) {
    IWindsorContainer container = new WindsorContainer();
    container.AddFacility<FactorySupportFacility>();
    container.AddComponentLifeStyle<Service>(LifestyleType.Transient);

  container.Register(Component.For<HttpRequestBase>()
      .LifeStyle.PerWebRequest
      .UsingFactoryMethod(() => new HttpRequestWrapper(HttpContext.Current.Request)));

  container.Register(Component.For<HttpContextBase>()
      .LifeStyle.PerWebRequest
      .UsingFactoryMethod(() => new HttpContextWrapper(HttpContext.Current)));  
}

By using HttpRequestBase instead of HttpRequest you can easily mock it out for testing. Also, don’t forget to register PerWebRequestLifestyleModule in your web.config.

 

About eagle081183

Passionate, Loyal
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s