Understanding MVC 3
Understanding MVC 3

In MVC framework the MVC-Router collects all the data from the URL and HTTP Request and then pass them down to the MVC-Handler as form of “RequestContext”. MVC-Handler then finds out the appropriate “Controller” that can handle than request. While searching for appropriate “Controller” to handle the request MVC-Handler scans all the classes within the project including the referenced libraries. It follows the following four criterias while searching:
a) Is the class public
b) Is the class concrete (meaning it is not an abstract class or an interface)
c) Does it implement the “IController” interface
d) Does it have “Controller” at the end of its name.

Remember that, by convention all the classes are kept in a folder called “Controllers” which is completely optional.

“IController” interface has only one method called “Execute” that takes only one argument called “requestContext”. This “requestContext” is of type “RequestContext” and carries all the necessary information about the HTTP request and any passed-in parameter.

public interface IController {
    void Execute (RequestContext requestcontext);
}

When we inherit from the “Controller” class the entire picture looks like the following

 

Controllers are just .cs file that has a public class inherited from “Controller” class.

When “ControllerBase” implements the “IController” it practically calls the protected “Execute” method that looks like below

void IController.Execute(RequestContext requestContext)
    {
      this.Execute(requestContext);  
 }

The protected “Execute” method inside the “ControllerBase” class looks like below

protected virtual void Execute(RequestContext requestContext)
    {
      if (requestContext == null)
        throw new ArgumentNullException("requestContext");
      if (requestContext.HttpContext == null)
        throw new ArgumentException(MvcResources.ControllerBase_CannotExecuteWithNullHttpContext, "requestContext");
      this.VerifyExecuteCalledOnce();
      this.Initialize(requestContext);
      using (ScopeStorage.CreateTransientScope())
        this.ExecuteCore();
    }
protected abstract void ExecuteCore();

Explain 'Execute'

The last line inside the “Execute” method is the fun bit. It calls the the “ExecuteCore” method. But, the “ExecuteCore” is an abstract method (without implementation), meaning this method can be called from a derived class only. We know from the diagram above that the “Controller” class is derived from the “ControllerBase” class. So, when the “ControllerBase” calls the “ExecuteCore” method actually it calls the “ExecuteCore” method of the derived class. And the “ExecuteCore” method inside the “Controller” class looks like following: 

protected override void ExecuteCore()
    {
      this.PossiblyLoadTempData();
      try
      {
        string requiredString = this.RouteData.GetRequiredString("action");
        if (this.ActionInvoker.InvokeAction(this.ControllerContext, requiredString))
          return;
        this.HandleUnknownAction(requiredString);
      }
      finally
      {
        this.PossiblySaveTempData();
      }
    }

So, When we create a new controller in MVC3, it automatically derives from the “Controller” class which in turn derives from the “ControllerBase” class that implements the “IController”. As a result, we call the “Execute” method of the “IController” class that in turn calls the “Execute” method of the “ControllerBase” class which in turn calls the “ExecuteCore” method of the derived class “Controller”.

Explain 'ExecuteCore'

Inside this “ExecuteCore” method the “InvokeAction” method is called on the “ActionInvoker”. “ActionInvoker” is an instance of type “ControllerActionInvoker” that implements the “IActionInvoker” that has only “InvokeAction” method. So, practically the “InvokeAction” of the “ControllerActionInvoker” gets called.

Inside the “InvokeAction” method “InvokeActionResult” method gets called which in turn calls the “ExecuteResult” method on the passed-in “ActionResult”. The methods look file the following:

public virtual bool InvokeAction(ControllerContext controllerContext, string actionName)
    {
      ...some code...
      ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(controllerContext);
      ActionDescriptor action = this.FindAction(controllerContext, controllerDescriptor, actionName);
      ...some code
      AuthorizationContext authorizationContext = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, action);
      if (authorizationContext.Result != null)
      {
        this.InvokeActionResult(controllerContext, authorizationContext.Result);
      }
...some more code...
      return true;
    }
 
protected virtual void InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
    {
      actionResult.ExecuteResult(controllerContext);
    }

Finding correct view

The passed-in “ActionResult” in the “ExecuteResult” is of type “ActionResult” which is an abstract class and there by the “ExecuteResult” method is also an abstract method(without implementation). It gets called on the derived class, which is the “ViewResultBase” class. Inside the “ExecuteResult” of the “ViewResultBase” the “FindView” method gets called which is also an abstract method (without implementation). So, when it calls the “FindView” method it practically gets called from the derived class, which in this case is the “ViewResult” class.

public override void ExecuteResult(ControllerContext context)
    {
     ...some code….
      if (this.View == null)
      {
        viewEngineResult = this.FindView(context); //Calling the FindView method here
        this.View = viewEngineResult.View;
      }
      this.View.Render(new ViewContext(context, this.View, this.ViewData, this.TempData, output),       output); //Calling the Render method here
      if (viewEngineResult == null)
        return;
      viewEngineResult.ViewEngine.ReleaseView(context, this.View);
    }

How data get passed to view

The “FindView” method needs a viewName and/or masterName in order to find the appropriate view. And how does a view gets all this info? Well, the answer is, when we call the “View” method with required parameter we essentially create a new “ViewResult” object with all these information. There are many implementations of the “View” method, one such is:

protected internal virtual ViewResult View(string viewName, string masterName, object model)
    {
      if (model != null)
        this.ViewData.Model = model;
      ViewResult viewResult = new ViewResult();
      viewResult.ViewName = viewName;
      viewResult.MasterName = masterName;
      viewResult.ViewData = this.ViewData;
      viewResult.TempData = this.TempData;
      return viewResult;
    }

Both, “ViewResult” and the “ControllerBase” class have a public property called “ViewData” which is practically implements the “IDictionary” interface that has a public property called “Model” which is just an “object”. That’s how, when we pass any domain-model or view-model to the “View” method, the view gets to know about the model and renders it. The rendering gets called inside the “ExecuteResult” method of the “ViewResultBase” as well and it look like below:

public override void ExecuteResult(ControllerContext context)
    {
     ...some code….
      if (this.View == null)
      {
        viewEngineResult = this.FindView(context); //Calling the FindView method here
        this.View = viewEngineResult.View;
      }
      this.View.Render(new ViewContext(context, this.View, this.ViewData, this.TempData, output), output); //Calling the Render method here
      if (viewEngineResult == null)
        return;
      viewEngineResult.ViewEngine.ReleaseView(context, this.View);
    }

 

February 23, 2016
Jahan Sarwar