Advanced Routing

As mentioned at the end of Chapter 9, routing is simple to learn yet challenging to master. Here we describe a few advanced tips Phil recommends to simplify some otherwise tricky routing scenarios.

RouteMagic

In Chapter 9, we mentioned the RouteMagic project, which is an open source project available on CodePlex at http://routemagic.codeplex.com/.

Install-Package RouteMagic.Mvc

This project is also available as a NuGet package appropriately named RouteMagic. RouteMagic is a pet project of Phil Haack, one of the authors of this book, and provides useful extensions to ASP.NET Routing that go above and beyond what's included “in the box.”

One useful extension included in the RouteMagic package is support for redirect routes. As noted usability expert Jakob Nielsen has recommended, “persistent URLs don't change,” and redirect routes will help you support that.

One of the benefits of routing is that you can change your URL structure all you want during development by manipulating your routes. When you do so, all the URLs in your site are updated automatically to be correct, which is a nice feature. But once you deploy your site to the public, this feature becomes a detriment, as others start to link to the URLs you've deployed. You don't want to change a route at this point and break every incoming URL.

Unless…you properly redirect. After installing RouteMagic, you'll be able to write redirect routes which take in an old route and redirect it to a new route, as follows:

var newRoute = routes.MapRoute("new", "bar/{controller}/{id}/{action}");
routes.Redirect(r => r.MapRoute("oldRoute",
 "foo/{controller}/{action}/{id}")
).To(newRoute);

For more information on RouteMagic, visit the RouteMagic CodePlex website. We think you'll find it to be an indispensable tool for your routing needs.

Editable Routes

In general, once you deploy your ASP.NET MVC application, you can't change the routes for your application without recompiling the application and redeploying the assembly where your routes are defined.

This is partly by design because routes are generally considered application code, and should have associated unit tests to verify that the routes are correct. A misconfigured route could seriously tank your application.

Having said that, there are many situations in which the ability to change an application's routes without having to recompile the application comes in very handy, such as in a highly flexible content management system or blog engine.

The RouteMagic project just mentioned includes support for routes that can be modified while the application is running. Begin by adding a new Routes class to the App_Start directory of an ASP.NET MVC 4 application (see Figure 15.12).

Next, use Visual Studio's Properties dialog to mark the file's Build Action as “Content” so that it's not compiled into the application, as shown in Figure 15.13.

The authors have intentionally excluded the Routes.cs file from build-time compilation because we want it to be compiled dynamically at run time. Following is the code for Routes.cs. (Don't worry about entering this code manually; it's provided as a NuGet package at the end of this section.)

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

public class Routes : IRouteRegistrar
{
    public void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", 
                action = "Index", 
                id = UrlParameter.Optional }
        );
    }
}
Note
The RouteMagic compilation system will be looking for a class named Routes with no namespace. If you use a different class name or forget to remove the namespace, the routes won't be registered.

The Routes class implements an interface named IRouteRegistrar that is defined in the RouteMagic assembly. This interface defines one method, RegisterRoutes.

Next, you'll change the route registration in App_Start/RouteConfig.cs to use a new extension method to register the routes:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using RouteMagic;

namespace Wrox.ProMvc4.EditableRoutes
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            RouteTable.Routes.RegisterRoutes("∼/App_Start/Routes.cs");
        }
    }
}

With this in place, you can now change routes within the Routes.cs file in App_Start directory after you've deployed the application without recompiling your application.

To see this in action, you can run the application and notice the standard home page comes up. Then, without stopping the application, alter the default route so the Account controller and Login action are set as route defaults:

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

public class Routes : IRouteRegistrar
{

    public void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Account",
                action = "Login",
                id = UrlParameter.Optional }
        );
    }
}

When you refresh the page, you'll see that the Login view is now displayed.


Editable Routes: The Gory Details
The previous section explains all you need to know to use editable routes. In case you're interested, here's how it works.
Usage seems simple enough, but that's because we've hidden all the magic in an extension method on RouteCollection. This method uses two tricks that allow us to dynamically generate the routing code in medium trust, without causing an application restart:
1. We use the ASP.NET BuildManager to dynamically create an assembly from the Routes.cs file. From that assembly, we can create an instance of the type Routes and cast it to IRouteHandler.
2. We use the ASP.NET Cache to get a notification of when the Routes.cs file changes, so we'll know it needs to be rebuilt. The ASP.NET Cache allows us to set a cache dependency on a file and a method to call when the file changes (invalidating the cache).
Here's the code that RouteMagic is using to add a cache dependency pointing to Routes.cs and a callback method that will reload the routes when Routes.cs is changed:
using System;
using System.Web.Compilation;
using System.Web.Routing;
using RouteMagic.Internals;

namespace RouteMagic
{

    public static class RouteRegistrationExtensions
    {

        public static void RegisterRoutes(this RouteCollection routes,
            string virtualPath)
        {
            if (String.IsNullOrEmpty(virtualPath))
            {
                throw new ArgumentNullException(”virtualPath”);
            }
            routes.ReloadRoutes(virtualPath);
            ConfigFileChangeNotifier.Listen(virtualPath, 
                                            routes.ReloadRoutes);
        }
        static void ReloadRoutes(this RouteCollection routes, 
                                 string virtualPath)
        {
            var assembly = BuildManager.GetCompiledAssembly(                            virtualPath);
            var registrar = assembly.CreateInstance(”Routes”) 
                            as IRouteRegistrar;
            using (routes.GetWriteLock())
            {
                routes.Clear();
                if (registrar != null)
                {
                    registrar.RegisterRoutes(routes);
                }
            }
        }
    }
}
One more interesting bit: The file change notifications are implemented using the ConfigFileChangeNotifier from ASP.NET team member David Ebbo's work on the ASP.NET Dynamic Data scaffolding system. For that code and more technical background, see Phil Haack's post at http://haacked.com/archive/2010/01/17/editable-routes.aspx.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset