Brian Mains

Catch me on linked in at: http://linkedin.com/in/brianmains, or follow me on twitter at: @brianmains.

Working with Web Forms and MVC: Bridging the Gap - Context

I've spent some time figuring out how to bridge the gap between web forms and ASP.NET MVC style of development.  Just because the UI works differently, doesn't mean the actual framework works in a different way.  If you use .NET 3.5 SP 1 for both your web forms and MVC style development, it is helpful to come up with a helper component to serve up the context.  Why would I suggest this?  Well, in web forms, you can access the current context information by accessing System.Web.HttpContext.Current, which returns the current HttpContext being executed.  The HttpContext object has an array of services (request, response, etc.) that you can make use of.  This is available in ASP.NET MVC in the controller too, via the ControllerContext.HttpContext reference.

The difference between the two is that the former uses an HttpContext object, while MVC uses an object of type HttpContextBase in System.Web.Abstractions.DLL.  The context is a reference to HttpContextWrapper, which inherits from HttpContextBase, and provides you with all of the services previously mentioned.  So basically, you are working with the same thing, but not the same object.  But if you use 3.5 for all of your development, you can use the same object to leverage both, by creating a helper class and always referring to this for your context.

public static class HttpWebContext
{
    public static HttpContextBase GetContext()
    {
         return new HttpContextWrapper(HttpContext.Current);
    }
}

This works in web forms because this is how it works anyway, while MVC uses this in its underlying architecture (if you use a tool like Reflector you can dig down into the code to find it).  And so this common component shares the context across two environments, and its isolated  and follows the Singular Repsonsibility Principle [SRP].  Now what about testability, because your internal components will be using this, and the http context won't be available in a testing environment (since it's web framework specific).  For instance, your controller may do something like:

public ActionResult View()
{
    var context = HttpWebContext.GetContext();
    //use the context in some way

   return View();
}

So how can that type of method be mocked?  If you use TypeMock, this can be done easily:

var ctx = Isolate.Fake.Instance<HttpContextBase>();
var requestFake = Isolate.Fake.Instance<HttpRequestFake>();
Isolate.WhenCalled(() => ctx.Request).WillReturn(requestFake);
//Additional faking here

Isolate.WhenCalled(() => HttpWebContext.GetContext()).WillReturn(ctx);

For Moq, this is harder because it doesn't mock statics; so you could make it an instance-based approach, or you could use a provider approach.  For instance, create a provider that has:

public abstract class ContextProvider
{
    public HttpContextBase GetContext();
}

Have two implementations, one for returning the current context like we have above, and have another returning a faked http context that inherits from HttpContextBase, and then store this reference in the configuration  file or pass it in as a parameter to a class. You could get kind of crazy with it, but by using the provider approach, it helps you differentiate the web environment and test environment without exceptions occurring.

Would this approach work in .NET 2.0?  Well, the great feature about 3.5 is the System.Web.Abstractions, which contains the HttpContextBase class that handles this for you.  So if you can use 3.5, you can leverage this API for your needs.  Otherwise, you would have to create your own wrapper, which is possible but tedious (since it's such a big class).

Posted: Sat, Nov 7 2009 11:02 by bmains | with 2 comment(s)
Filed under: ,

Comments

jettaclowe said:

primary level atlantic efficiency suggests observations related possible

# November 8, 2009 12:11 AM

allysonche said:

domestic processes occur results

# November 9, 2009 12:02 AM
Leave a Comment

(required) 

(required) 

(optional)
 

(required) 

If you can't read this number refresh your screen
Enter the numbers above: