Creating a custom ActionResult

OK so now that we know a little more about ActionResults , let’s create a new one! I’ll go with a simple one , a personalized ViewResult.

It’ll be pretty much like standard ViewResult. First we’ll derive a base class from ActionResult , this abstract base class will take care of the ViewData , TempData , ExecuteResult method and stuff. Then we’ll derive our ViewResult from that base class , FindView there and maybe add some logic into that.

I’ll call our little action result , “MaryLouResult” from now on. I’ve already admitted I’m bad at naming stuff , so I’ll just stick with the song ( Mary Lou – Sonata Arctica ) I’m listening at the moment.

So let’s start with MaryLouBase!

protected abstract ViewEngineResult FindView(ControllerContext context);

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);
        View = result.View;
    }

    TextWriter writer = context.HttpContext.Response.Output;
    ViewContext viewContext = new ViewContext(context, View, new ViewDataDictionary(), TempData, writer);
    View.Render(viewContext, writer);

    if (result != null)
    {
        result.ViewEngine.ReleaseView(context, View);
    }
}

Nothing fancy here , actually I’ve just copy&pasted the ExecuteResult method of ViewResultBase class as it’s pretty straight forward. A few null checks , then FindView then ReleaseView.

You can also find ViewData and TempData implementations in ViewResultBase code or in the solution file at the bottom of this article.

Of course we could have simply used ViewResultBase and derive our MaryLouResult from that , but I just wanted to show you there is nothing magical about ViewResultBase class , you can just create another one as you like ( or totally skip it an derive your result from ActionResult ).

Now that we have a base class to handle ExecuteResult for us , all we need now is a MarylouResult with FindView method.

 

public class MaryLouResult : MaryLouResultBase
{
    private string _viewName { get; set; }
    private string _masterName { get; set; }
    private object _model { get; set; }

    public MaryLouResult(string viewName = "", string masterName = "", object model = null)
    {
        _viewName = viewName;
        _masterName = masterName;
        _model = model;
    }

    protected override ViewEngineResult FindView(ControllerContext context)
    {
        //Yeap you can get your Controller from here
        var faschoController = (context.Controller as FaschoController);

        //And check if it's an Ajax Request
        var ajax = context.HttpContext.Request.IsAjaxRequest();
        var FaschoAjax = faschoController.IsAjax;

        //Or if the user is Authenticated
        var auth = context.HttpContext.User.Identity.IsAuthenticated;
        var FaschoAuth = faschoController.IsAuthenticated();

        //Or if the user is actually an Admin
        var admin = context.HttpContext.User.IsInRole("admin");
        var FaschoAdmin = faschoController.IsAdmin();

        ViewData = new ViewDataDictionary(_model);

        //Then you can add some logic here as you like to select the view or the masterpage
        if ((context.Controller as FaschoController).IsAjax)
            _masterName = null;

        var result = ViewEngines.Engines.FindView(
        context,
        string.IsNullOrWhiteSpace(_viewName) ? ViewName : _viewName,
        _masterName
        );

        if (result.View != null)
        {
            return result;
        }

    }
}

OK so let’s see , we have a few fields for view name and master age name , then a a simple constructor and then the real part , FindView method.

FindView method gets a ControllerContext as a parameter which includes stuff like , current controller and HttpContext so we have lots of information in our hands just in case.

I really don’t have a special thing for Master pages but again the first thing came to my mind was playing with that.

As you can see you can use both HttpContext and your custom Controller ( if you have one ) from here. This means we can just check if the request is an Ajax request and change our FindView call according to that. Or maybe return Error Page if user is not authenticated?

I’ll have to say it tho , I don’t really like putting this kind of logic here. It feels out of place and I already usemy little Fascho Controller for these stuff.

This little example here was a little limited as it’s just a personalized ViewResult but actually there is literally no limit to what you can do with ActionResults. I’ll probably add a few more examples on ActionResults in future too.

You may also want to check these out ;

File Download Action Result by Phil Haack – Old but a very nice example

Image Result by Maarten Balliauw

Visual Studio 2010 Solution

Leave a Reply