Almost all our Action in Mvc returns some kind of an ActionResult ( surprise! ). Or let’s say , they return a class derived from ActionResult , such as ;
· ViewResult
· RedirectResult
· RedirectToRouteResult
· JsonResult
But how does this ActionResults work? It pretty simple actually ;
namespace System.Web.Mvc { public abstract class ActionResult { public abstract void ExecuteResult(ControllerContext context); } }
Told you! It’s just an abstract class with ExecuteResult function.
So let’s look into one of the most commonly used ActionResult , ViewResult and ViewResultBase ( Why I can’t link directly to a particular file , *sigh* ).
Abstract base class , **ViewResultBase** first ;
namespace System.Web.Mvc { using System; using System.Diagnostics.CodeAnalysis; public abstract class ViewResultBase : ActionResult { private TempDataDictionary _tempData; private ViewDataDictionary _viewData; private ViewEngineCollection _viewEngineCollection; private string _viewName; //Lots of properties below , the best part , ExecuteResult , is at the bottom [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "This entire type is meant to be mutable.")] public TempDataDictionary TempData { get { if (_tempData == null) { _tempData = new TempDataDictionary(); } return _tempData; } set { _tempData = value; } } public IView View { get; set; } [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "This entire type is meant to be mutable.")] public ViewDataDictionary ViewData { get { if (_viewData == null) { _viewData = new ViewDataDictionary(); } return _viewData; } set { _viewData = value; } } [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "This entire type is meant to be mutable.")] public ViewEngineCollection ViewEngineCollection { get { return _viewEngineCollection ?? ViewEngines.Engines; } set { _viewEngineCollection = value; } } public string ViewName { get { return _viewName ?? String.Empty; } set { _viewName = value; } } public override void ExecuteResult(ControllerContext context) { if (context == null) { throw new ArgumentNullException("context"); } if (String.IsNullOrEmpty(ViewName)) { ViewName = context.RouteData.GetRequiredString("action"); } ViewEngineResult result = null; if (View == null) { result = FindView(context); //this is the part we care about at the moment View = result.View; } ViewContext viewContext = new ViewContext(context, View, ViewData, TempData); View.Render(viewContext, context.HttpContext.Response.Output); if (result != null) { result.ViewEngine.ReleaseView(context, View); //And probably this } } protected abstract ViewEngineResult FindView(ControllerContext context); } }
Wow , that’s a lot of code. But actually it’s just a few properties for stuff like ViewData and TempData. What we really care about here is ExecuteResult method ( at the bottom ). As you can see , ExecuteResult ( the only thing we really need for a custom ActionResult ) does 2 main things ; go find the view ( FindView ) and send it to ViewEngine ( ReleaseView ).
And the last part of our ActionResult , **ViewResult** ;
public class ViewResult : ViewResultBase { private string _masterName; public string MasterName { get { return _masterName ?? String.Empty; } set { _masterName = value; } } protected override ViewEngineResult FindView(ControllerContext context) { ViewEngineResult result = ViewEngineCollection.FindView(context, ViewName, MasterName); //Obviously this gives you a good opportunity to interfere View & MasterPage selections if (result.View != null) { return result; } //I took out the part about error generation for now } }
So all ViewResult does , is to use our ViewEngineCollection to find the page ( view ) we want. Remember , then it goes back to ViewResultBase and releases the view and we’re pretty much done with ActionResult , ViewEngine will take care of the rest.
Let’s have a look at how this all executes ;
Client Requests a Page
Controller is Created
-> Controller – OnActionExecuting runs
Action runs
->ViewResult is Created ( at return View(); )
ActionFinishes
-> Controller – OnActionExecuted runs
-> Controller – OnResultExecuting and OnResultExecuted runs
-> ViewResultBase – ExecuteResult runs
-> ViewResult – FindView runs
-> ViewResultBase send the view to ViewEngine ( ReleaseView )
Some magic happens after that which I know nothing of yet
Client gets the html , and hopefully happy now
You can also check this MSDN article about the execution process.
And Codeplex page of Asp.Net for the source code of Mvc
In next post , we’ll create a new custom ActionResult and play with it a little…