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…