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