29

This may not be the correct way to use controllers, but I did notice this problem and hadn't figured out a way to correct it.

public JsonResult SomeControllerAction() {

    //The current method has the HttpContext just fine
    bool currentIsNotNull = (this.HttpContext == null); //which is false    

    //creating a new instance of another controller
    SomeOtherController controller = new SomeOtherController();
    bool isNull = (controller.HttpContext == null); // which is true

    //The actual HttpContext is fine in both
    bool notNull = (System.Web.HttpContext.Current == null); // which is false        

}

I've noticed that the HttpContext on a Controller isn't the "actual" HttpContext that you would find in System.Web.HttpContext.Current.

Is there some way to manually populate the HttpContextBase on a Controller? Or a better way to create an instance of a Controller?

tereško
  • 56,151
  • 24
  • 92
  • 147
hugoware
  • 33,265
  • 24
  • 58
  • 70

5 Answers5

63

For now I'm going to do the following. This seems to be an acceptable fix...

public new HttpContextBase HttpContext {
    get {
        HttpContextWrapper context = 
            new HttpContextWrapper(System.Web.HttpContext.Current);
        return (HttpContextBase)context;                
    }
}

Where this is added to a Controller class these Controllers are inheriting from.

I'm not sure if the HttpContext being null is the desired behavior, but this will fix it in the meantime for me.

hugoware
  • 33,265
  • 24
  • 58
  • 70
  • Thank you so much for deciphering the new way of working between the two types. I had an old class I was trying to use from an MVC controller that consumed an HttpContext object. Now I have a class that consumes an HttpContextBase object with a constructor overload that will convert between HttpContext and HttpContextBase using the HttpContextWrapper constructor you mentioned. – patridge Jun 12 '09 at 20:31
  • +1 This is a wonderful snippet! I added to it a bit though. I wrapped your wrapper with a ContextHelper class which exposes only the properties I need out of your underlying HttpContext proeprty to allow me to then create a mock of my ContextHelper. StructureMap then allows me to swap what I need in and out. Then I created a WebSite object to act as a view API which is exposed off of all sorts of base classes for views, controllers, etc. I will have to mention this in my book (ASP.NET MVC Cookbook) if you don't mind: http://groups.google.com/group/aspnet-mvc-2-cookbook-review – Andrew Siemer May 07 '10 at 21:21
  • @Hugoware `(HttpContextBase)` cast is redundant. Please remove it – Andrus Dec 16 '15 at 19:27
  • How is this used though? Trying to add a user to a role from another controller besides the account controller. – Nathan McKaskle Feb 15 '17 at 18:28
24

Controllers are not designed to be created manually like you're doing. It sounds like what you really should be doing is putting whatever reusable logic you have into a helper class instead.

Brad Wilson
  • 61,606
  • 8
  • 70
  • 82
  • 1
    Brad, do you have somewhere that can help with understanding MVC design and best practices? MVC has been cool so far, but most examples I've found aren't very complex. They only go over the simple instances like updating a single record. – hugoware Oct 22 '08 at 14:53
  • Brad, I have the same issue, and this is also coming from a helper class, just like you recommended. I tried the fix provided by Hugoware (below), and that fixed it. Is this the proper way to do this? – Mark Kadlec Jul 29 '10 at 03:37
5

The HttpContext, in the ControllerContext is null because it is not set when the controller is created. The contructor of the controller does not assign this property, so it will be null. Normally, the HttpContext is set to the HttpContext of the ControllerBuilder class. Controllers are created by the ControllerBuilder class, followed by the DefaultControllerFactory. When you want to create your own instance of a controller, you can use the ExecuteMethod of the controller with your own ControllerContext. You don't want to do that is a real application. When you get some more experience with the framework you will find the appropriate method to do want you want. When you need ControllerContext in Unit test, you can use a mocking framework to mock the ControllerContext or you can class faking it.

You can find a model of the request flow in asp.net mvc on this blog.

When your new to Asp.net mvc, it's worth the effort to download the source code and read an trace the route how a request is processed.

Paco
  • 8,184
  • 3
  • 28
  • 41
0

Is it that you want to use some functionality from the controller? Or have the controller perform an action?

If it's the former, maybe that's some code that should be split out into another class. If it's the latter, you can do this to simply have that controller do a specific action:


return RedirectToAction("SomeAction", "SomeOtherController", new {param1 = "Something" });

mmacaulay
  • 2,913
  • 21
  • 27
0

Are you using a controller factory? If so, how are you registering components?

I ran into this problem where I had inadvertently added an HttpContext-based dependency as a Singleton, rather than Transient in Windsor.

HttpContext was null for all but the first request. It took me a while to track down that one.

Ben Scheirman
  • 39,034
  • 20
  • 96
  • 135