In this tip, I demonstrate how you can eliminate controller methods that simply return views. I show you how to use the HandleUnknownAction method to handle every request against a controller automatically.

I saw Phil Haack use the following tip in a demo that he presented. I thought that it was such a great idea that I had to share it.

There is no good reason to write code unless there is a good reason to write code. I discover that I write a lot of controller actions that do nothing more than return a view. For example, consider the CustomerController in Listing 1.

Listing 1 – CustomerController.vb

Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Web
Imports System.Web.Mvc

Namespace Tip22.Controllers
    Public Class CustomerController
        Inherits Controller

        Public Function Index() As ActionResult
            Return View()
        End Function

        Public Function Details() As ActionResult
            Return View()
        End Function

        Public Function Help() As ActionResult
            Return View()
        End Function

    End Class
End Namespace

Listing 1 – CustomerController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
 
namespace Tip22.Controllers
{
    public class CustomerController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }
 
        public ActionResult Details()
        {
            return View();
        }
        public ActionResult Help()
        {
            return View();
        }
     
    }
}

This controller includes three actions that return three different views. Each of these actions contains a single line of code. In fact, each of these actions contains exactly the same line of code. This code reeks of needless work. How can we fix it?

The Controller class includes a method, named the HandleUnknownAction() method, that executes whenever you attempt to invoke an action on a controller that does not exist. The controller in Listing 2 takes advantage of the HandleUnknownAction() method to render views even when a corresponding controller method does not exist.

Listing 2 – HomeController.vb

Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Web
Imports System.Web.Mvc
 
Namespace Tip22.Controllers
    <HandleError> _
    Public Class HomeController
        Inherits Controller
 
        Public Function Details() As ActionResult
            ViewData("message") = "Hello from controller action!"
            Return View()
        End Function
 
        Protected Overrides Sub HandleUnknownAction(ByVal actionName As String)
            Me.View(actionName).ExecuteResult(Me.ControllerContext)
        End Sub
 
    End Class
End Namespace

Listing 2 – HomeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
 
namespace Tip22.Controllers
{
    [HandleError]
    public class HomeController : Controller
    {
        public ActionResult Details()
        {
            ViewData["message"] = "Hello from controller action!";
            return View();
        }
 
        protected override void HandleUnknownAction(string actionName)
        {
            this.View(actionName).ExecuteResult(this.ControllerContext);
        }
 
    }
}

When you use the controller in Listing 2, you can call any action and the controller will attempt to return a view that corresponds to the action. You don’t need to explicitly code an action method for each view.

Notice that the controller includes a Details() action. When you need to pass ViewData, then you need to explicitly code the action method.

If you liked this blog post then please Subscribe to this blog.
posted on Monday, July 21, 2008 11:12 PM | Filed Under [ ASP.NET ASP.NET MVC Tips ]

Comments

Gravatar
# re: ASP.NET MVC Tip #22 -- Return a View without Creating a Controller Action
Posted by Webdiyer
on 7/22/2008 1:45 AM

Thank you for your great tips!
Gravatar
# re: ASP.NET MVC Tip #22 -- Return a View without Creating a Controller Action
Posted by haacked
on 7/22/2008 6:44 AM

As Eilon pointed out to me, you can accomplish the same thing using routing and a parameterized action method.<br /><br />Route: url="/show/{viewName}", defaults={controller="home", action=showview}<br /><br /> public ActionResult ShowView(string viewName) {<br /> return View(viewName);<br />}<br /><br />And now, you don't have to write action methods for each view in the views/home directory, you can just go to /show/viewname
Gravatar
# re: ASP.NET MVC Tip #22 -- Return a View without Creating a Controller Action
Posted by joshka
on 7/22/2008 1:18 PM

Hi Stephen.<br />Would it be possible to provide a full text feed from your site. I generally read your blog in an RSS reader, and this is one of the few that I have to click through to read the actual article.<br />A couple of suggestions for your blog theme that hopefully won't go astray - if you cssify your vb code with a vbwrapper class instead of csharpwrapper css class, you could provide some quick javascript to hide one or the other. An option to expand all code samples for easier reading would be pretty nice also. The scrolling textboxes are nice at first, but are an annoyance when you want to read the code with the article.
Gravatar
# re: ASP.NET MVC Tip #22 -- Return a View without Creating a Controller Action
Posted by http://
on 7/22/2008 2:46 PM

@joshka - thanks for the feedback and for reading my blog. I have to publish excerpts because feedburner places a size limit on blog entries (feedburner stops broadcasting a blog when it gets too long). I'll look into a method for hiding/displaying different code versions. Thanks!
Gravatar
# re: ASP.NET MVC Tip #22 -- Return a View without Creating a Controller Action
Posted by http://
on 7/22/2008 2:59 PM

What if the client puts in a URL for a view that does not exist? I assume they get an error of some sort? What if we would like to display a "File (view) not found" page instead?<br /><br />Thanks.
Gravatar
# re: ASP.NET MVC Tip #22 -- Return a View without Creating a Controller Action
Posted by http://
on 7/22/2008 8:39 PM

I don't see why this would be good other then for DRY. If you go to a page that doesn't exist, you will encounter an exception (I would think, never tested it though) that the view doesn't exist. At this point, does MVC push the user to the error page or does an ugly exception page show up?
Gravatar
# re: ASP.NET MVC Tip #22 -- Return a View without Creating a Controller Action
Posted by Andrei Rinea
on 10/18/2008 7:54 PM

Great tip! I'll try it out. I just love a DRY tip :)
Gravatar
# re: ASP.NET MVC Tip #22 -- Return a View without Creating a Controller Action
Posted by Thor Larholm
on 11/18/2008 10:33 AM

This works great if you have actually created a corresponding view and simply want to leave out the glue code of returning a View with the same name as the action.<br /><br />However, if you have not created a corresponding view you will receive an InvalidOperationException when you trigger the ExecuteResult method. This is in contrast to the "404 Not Found" message you would otherwise receive on an unknown action.<br /><br />If you want to be both DRY and able to handle unknown action/view combinations you can add a custom route as suggested by "haacked" and then explicitly provide a fallback action by overriding the OnException method.<br /><br />routes.MapRoute(<br /> "Home",<br /> "Home/{viewName}",<br /> new { controller = "Home", action = "ShowUnknownView" }<br />);<br /><br /><br />public ActionResult ShowUnknownView(string viewName)<br />{<br /> return View(viewName);<br />}<br /><br />protected override void OnException(ExceptionContext filterContext)<br />{<br /> filterContext.HttpContext.Response.Redirect("/Home");<br />}<br /><br /><br />
Comments have been closed on this topic.