1

HttpContextWrapper and HttpContextBase, as explained here, were introduced to make HttpContext more mockable/testable.

I'm trying to use it with S#arp Architecture, and hitting some problems.

My MVC Controllers are set up to accept an HttpContextBase argument in the constructor, and during Application_Start, HttpContextBase is registered with Castle.Windor as follows:

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

This seemed to work OK for a bit, but then I realised Castle is only running that Factory method once, so all requests get the original HttpContextWrapper. Really it needs to be re-created for every request. The Castle.Windsor command for that would be:

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

... but it turns out that Castle.Windsor doesn't allow LifeStyle.PerWebRequest to be used within Application_Start (as explained here)

What should I be doing? Is there an easy way round this or should I give up on HttpContextWrapper and inject my own factory to make new ones as needed?

Community
  • 1
  • 1
codeulike
  • 22,514
  • 29
  • 120
  • 167

3 Answers3

8

My MVC Controllers are set up to accept an HttpContextBase argument in the constructor

You gotta be doing something extremely wrong here, so stop before it's too late and damage has been caused (material, moral and human casualties :-)). You already have the HttpContext inside the controller.

Don't register any HttpContexts in your DI framework. The HttpContext handling is the job of ASP.NET.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 1
    @jfar, I've leaked beer on my screen when I read the sentence `My MVC Controllers are set up to accept an HttpContextBase argument in the constructor`. – Darin Dimitrov Mar 28 '11 at 20:44
  • OK, but then what is the point of HttpContextWrapper and/or how do I mock the HttpContext that gets passed in by ASP.NET? – codeulike Mar 28 '11 at 21:12
  • @codeulike, well, personally I use [MVCContrib TestHelper](http://mvccontrib.codeplex.com/wikipage?title=TestHelper) for this purpose but there are like [40k alternatives](http://www.google.com/#sclient=psy&hl=en&q=asp.net+mvc+mock+httpcontext+unit+test&aq=f&aqi=&aql=&oq=&pbx=1&bav=on.2,or.r_gc.r_pw.&fp=48e89ff3ea888421). – Darin Dimitrov Mar 28 '11 at 21:14
  • By the way, its not that I'm creating an HttpContext, that really would be serious beer-spilling territory. Its more a case of creating an HttpContextWrapper at the appropriate time and wrapping it around the HttpContext that asp.net has made. The problem is getting Castle.Windor to do it at the right time. I'll look into the TestHelper and the, er, 40k other google results. Thanks. – codeulike Mar 28 '11 at 21:21
  • Hmm, I think I want a second opinion. I'm not sure that what I'm trying to do is all that different from this: http://stackoverflow.com/questions/3990879/is-it-safe-to-always-create-a-new-httpcontextwrapper .. if its Ok to do that, why isn't it OK to inject? – codeulike Mar 28 '11 at 21:37
  • @codeulike, the example you are referring is about making a classic ASP.NET web forms more unit testable. You, and correct me if I am wrong here (and if I am wrong please retag your question), are doing ASP.NET MVC which is very different than classic ASP.NET WebForms application. – Darin Dimitrov Mar 28 '11 at 21:39
  • I am using MVC. But if injecting an HttpContextWrapper factory is OK in classic ASP.NET (I think thats what you suggest in the other question?), why isn't it OK in MVC? – codeulike Mar 28 '11 at 21:48
  • @codeulike, in ASP.NET MVC a controller action already has an `HttpContext` injected by the ASP.NET MVC framework. And this context is already a mockable abstraction: `HttpContextBase`, so you don't need to do any additional plumbing. The plumbing is necessary in classic ASP.NET WebForms where there are no abstractions, only static crap like `HttpContext.Current` which is impossible to unit test. – Darin Dimitrov Mar 28 '11 at 21:49
  • Ah, I see. But when I'm creating Controller objects in my unit tests, how do I get my Mock HttpContextBase into the controllers? – codeulike Mar 28 '11 at 21:53
  • @codeulike, did you check [MvcContrib TestHelper](http://mvccontrib.codeplex.com/wikipage?title=TestHelper)? It's a framework supposed to do exactly this. You seem to be commenting a bit quickly here without verifying the references that I provided. Read the documentation, try things out, play with Rhino Mocks. If you encounter some specific problems don't hesitate to show what you have tried so far and ask another question, etc ... so that we have something constructive here. – Darin Dimitrov Mar 28 '11 at 21:54
  • @codeulike, btw you may checkout a [sample ASP.NET MVC project structure I wrote](https://github.com/darind/samplemvc) which uses MvcContrib TestHelper for unit testing controller actions. – Darin Dimitrov Mar 28 '11 at 22:04
  • I'm sure TestHelper would do it, but then I was sidetracked into discovering why what I was originally doing was 'extremely wrong'. I reckon I can make the Castle.Windsor method work, maybe using the Transient lifestyle. So, maybe a bit sub-optimal, but I think it could work as a lightweight controller testing fudge. But yes, I can see that TestHelper would sort this out for me, and also help with a bunch of other things. Thanks for your help, I understand the territory a lot better now. – codeulike Mar 28 '11 at 22:18
2

As Darin noted, it makes no sense to inject an HttpContext into an MVC controller. However, if you need it for other kind of services and also need it in Application_Start(), use an hybrid perwebrequest-transient lifestyle. Or, since it's trivial to build, just make it transient.

Mauricio Scheffer
  • 98,863
  • 23
  • 192
  • 275
0

As others have stated - you are doing it wrong. My big question is:

What are you doing that requires you to inject HttpContextBase in your controller? It might be more helpful to people wanting to help you if you would provide us more context about what you are really trying to do. Lets take Castle out of it and get down to what your controller is doing.

BTW, your controller already has a reference to HttpContext. If you are doing this for testability, there is nothing you need to do at the controller level. You would just need to mock the HttpContextBase object as needed in your controller tests.

Alec
  • 691
  • 4
  • 12
  • I was doing it for testability. You are right that mocking the HttpContextBase in the controller tests is easy, but I couldn't see any obvious way to inject the mock into the controllers, without a custom controller factory. Now I know that TestHelper provides exactly that. – codeulike Mar 29 '11 at 21:50