Setting up a minimal ASP.NET MVC project in Visual Studio, part 2

Now that we have a place to define our routes, we first need to reference System.Web.Mvc from our project. The ASP.NET MVC framework contains a RouteHandler called MvcRouteHandler. We will use this when defining our routes. The MvcRouteHandler will create an instance of MvcHandler to handle the actual request based on the route data in the RequestContext object. This route data must contain a value for the controller variable, which is used to instantiate a Controller. The System.Web.Mvc.Controller class that your controllers will typically inherit from also requires an action variable. Therefore, we have to make sure that when we add our routes they contain values for the controller and action variables, through the use of parameter segments in the URL and/or by specifying default values for those variables.

This is what our Router class looks like:

using System.Web.Mvc;
using System.Web.Routing;

namespace Mvc
{
    public static class Router
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            Route route = new Route("{controller}/{action}", new MvcRouteHandler());
            routes.Add(route);
        }
    }
}

This route will match all requests with a URL that has at least two segments so that the controller and index variables can be matched. When you run the application and navigate to ~/home/index it will still result in a 404 error though. That’s because there is no controller yet.

Adding controllers…

Once the MvcHandler has extracted the name of the controller from the route data it will ask a ControllerFactory to instantiate a controller1. The DefaultControllerFactory will first determine the type of the controller. The type of the controller is ultimately determined by the ControllerTypeCache which has a list of all public, non-abstract classes that implement IController with a name ending in Controller. It is customary to put our controller classes in a folder called Controllers.

The simplest controller we can add is below.

using System.Web.Mvc;

namespace Mvc.Controllers
{
    public class HomeController : Controller
    {
        public string Index()
        {
            return "Hello World!";
        }
    }
}

This controller has one action, the public method Index(). Now when we navigate to ~/home/index we should see the result of this method in our browser. The Index action of the HomeController makes for a good default action, so we will make these values the defaults in the route we define in the Router class:

public static void RegisterRoutes(RouteCollection routes)
{
    Route route = new Route(
        "{controller}/{action}",
        new RouteValueDictionary(new { Controller = "Home", Action = "Index" }),
        new MvcRouteHandler());
    routes.Add("Default", route);
}

You might expect that when we browse to ~/ that our action is executed, but it’s not. The ASP.NET Development Server just returns a directory Listing. This will be resolved by adding another project type guid to the project (see below).

…and views

Of course, returning a string is far from an ideal way of building a webpage, so let’s add a view to our application as well. The default location for views is the Views folder, further subdivided into folders for each controller. There is typically a view for each action on the controller, so in our case we add an Index view to the folder Views/Home. The standard ViewEngine is the WebFormViewEngine, which works with (almost) the same files as normal WebForms, the difference being the base class they inherit from.

When adding a new item to a project Visual Studio offers us a choice of several templates. To get access to the ASP.NET MVC templates we can add another project type guid to the project:

<ProjectTypeGuids>{603c0e0b-db56-11dc-be95-000d561079b0};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>

After reloading the project it has now become self-aware of its identity as an ASP.NET MVC project. Now when you add a new item there’s a new set of MVC templates available to choose from.

These pages and controls inherit from classes in the System.Web.Mvc assembly (you can see this in the <%@ Page %> directive). The WebFormsViewEngine uses the same compilation process as regular WebForms. This means we have to reference this assembly in the Web.config for the ASP.NET compiler to use it, otherwise the page parser will not be able to load these types:

<compilation debug="true">
    <assemblies>
        <add assembly="System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
    </assemblies>
</compilation>

When we add the MVC View Page called Index.aspx to the Views/Home folder it will be the page we see when we navigate to ~/home/index. For this we need to change our action to return an ActionResult using the View() method. The built-in conventions of mapping an action to a view in the Views folder will take care of the rest.

public ActionResult Index()
{
    return View();
}

The last thing we need to do is prevent browsing directly to the views. Browse to ~/views/home/index.aspx and you should see the contents of the view page. This is not what we want, so we will add a Web.config file to the Views folder to deny direct access to the views.

<?xml version="1.0"?>
<configuration>
    <system.web>
        <authorization>
            <deny users="*"/>
        </authorization>
    </system.web>
</configuration>

What else?

Adding the last project type guid to our project file has had one unexpected result. Before, browsing to ~/ would result in a directory listing from the ASP.NET Development Server, but as soon as we added the guid it will automagically match our route using the default values for controller and action.

Conclusion

In this post (and the previous post) we have seen how to set up an ASP.NET MVC project from scratch. Hopefully you now have a better understanding of all the different elements and how they work together. We have seen how routing is not strictly part of ASP.NET MVC, how the project type guids determine how a project behaves in Visual Studio and what we need at minimum to get started with this new framework.

Hope this helps!

Footnotes

  1. This is known as the factory design pattern, it allows us to specify a different ControllerFactory to control the way controllers are instantiated.

Comments