Understanding the IController and ControllerBase in ASP.NET MVC





5.00/5 (3 votes)
The tip describes about the IController interface and the ControllerBase class.
Introduction
Controllers in MVC are responsible for responding to user interactions, often making changes to the Model in response to user input. In short, controllers in the MVC pattern are concerned with the flow of the application, processing of the incoming data and providing data going out to the relevant View.
Whenever we add a controller to our MVC project, Visual Studio, creates a class whose name is suffixed with "Controller". This newly created class inherits from Controller
class, which makes it to behave as a controller. Alternatively, we can also create a controller by inheriting from ControllerBase
class or by implementing the IController
interface. This is possible as, Controller
class inherits ControllerBase
class, which in turn implements the methods of IController
interface. Let's go through ControllerBase
class and IController
interface and find out what methods each of them offer.
IController interface
IController interface, sole purpose is to execute some code when a request is made to a controller. This is how the interface looks like:
Note: We can get the source code from aspnetwebstack.codeplex.com/
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// See License.txt in the project root for license information.
using System.Web.Routing;
namespace System.Web.Mvc
{
public interface IController
{
void Execute(RequestContext requestContext);
}
}
IController
interface exposes Execute()
method, that gets executed when a request is made for the controller. It accepts an object of RequestContext
class, which encapsulates information about an HTTP request that matches a defined route, using the HttpContext
and RouteData
properties.
Thus, we can create a controller by implementing the IController
and implement its Execute()
method to do some work. For example the below MyCustomController
class, implements IController
and gives a body to the Execute()
method.
public class MyCustomController : IController
{
public void Execute(RequestContext requestContext)
{
string controller = requestContext.RouteData.Values["controller"] as string;
string action = requestContext.RouteData.Values["action"] as string;
requestContext.HttpContext.Response.Write(string.Format("Controller name - {0}", controller));
requestContext.HttpContext.Response.Write(string.Format("Action name - {0}", action));
}
}
Over here, we are fetching the controller and action names from the route values collection and to keep the example simple directly writing it to the response.
ControllerBase class
The abstract ControllerBase
class represents the base class for all MVC controllers. It implements the IController
interface's, Execute()
method which executes the specified request context. This is how the class looks like :
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// See License.txt in the project root for license information.
public abstract class ControllerBase : IController
{
protected virtual void Execute(RequestContext requestContext)
{
if (requestContext == null)
{
throw new ArgumentNullException("requestContext");
}
if (requestContext.HttpContext == null)
{
throw new ArgumentException(
MvcResources.ControllerBase_CannotExecuteWithNullHttpContext,
"requestContext");
}
VerifyExecuteCalledOnce();
Initialize(requestContext);
using (ScopeStorage.CreateTransientScope())
{
ExecuteCore();
}
}
protected abstract void ExecuteCore();
protected virtual void Initialize(RequestContext requestContext)
{
ControllerContext = new ControllerContext(requestContext, this);
}
internal void VerifyExecuteCalledOnce()
{
if (!_executeWasCalledGate.TryEnter())
{
string message = String.Format(CultureInfo.CurrentCulture,
MvcResources.ControllerBase_CannotHandleMultipleRequests, GetType());
throw new InvalidOperationException(message);
}
}
void IController.Execute(RequestContext requestContext)
{
Execute(requestContext);
}
}
The ControllerBase
class acts as a wrapper on top of the IController
interface. The Execute()
method of ControllerBase
class is responsible for creating the ControllerContext
, which provides the MVC specific context for the current request much in the same way that an instance of HttpContext provides the context for ASP.NET, providing request and response, URL and server information, among other elements.
We can see that, ControllerBase
class provides an implementation of Execute()
, but then it has another definition for IController.Execute()
, so the question is why is it so ?
By default, normally implemented interface method is public and is not virtual or abstract, so you can't override it in derived classes. So if we are creating a new Execute()
method inside ControllerBase
class, it wouldn't be accessible through the IController
interface by default when its own Execute()
method is to be called.
But by creating a new, protected virtual Execute()
method inside ControllerBase
class, which we will be calling from the explicitly implemented interface method (IController.Execute()
), allows derived classes (Controller
class) to override the ControllerBase
class Execute()
method without breaking the interface implementation.
Thus, we can create a controller by implementing the ControllerBase
and override it's ExecuteCore()
method to do some work. For example the below MyCustomController
class, inherits ControllerBase
and gives a body to the ExecuteCore()
method.
public class MyCustomController : ControllerBase
{
protected override void ExecuteCore()
{
string controllername = ControllerContext.RouteData.Values["controller"].ToString();
string actionName = ControllerContext.RouteData.Values["action"].ToString();
this.ControllerContext.HttpContext.Response.Write(
string.Format("Controller name - {0}", controllername));
this.ControllerContext.HttpContext.Response.Write(
string.Format("Action name - {0}", actionName));
}
}
Over here, we are fetching the controller and action names from the route values collection and to keep the example simple directly writing it to the response.
Controller's that implement IController
or inherit ControllerBase
directly, have to write down there own implementations for mapping the request URL with the execution of the appropriate action.