URL Rooting in ASP.NET (Web Forms)

If you are an ASP.NET MVC developer, you will certainly be aware of its default URL Routing behavior, where if for example you were to display a View named “Index” that was relying in a controller named “ProductsController”, you could request it with the following URL:

/products/index

On the other side, if you had a simple ASP.NET Web Forms project and not an MVC one, you would have to request the full path of the page that you wanted to display.

/full_path/index.aspx

You must know though, that it’s possible to support MVC like URL Routing in Web Forms too. This post will show you how to create Hackable URLs in your Web Forms project. To start with, open Visual Studio and create a new Empty ASP.NET Web Application project. Create a new WebForm named “Default.aspx” page in the root directory and paste the following contents.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="AspNetUrlRouting.Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Default.aspx</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h1>This is the Default.aspx</h1>
    </div>
    </form>
</body>
</html>

It’s a simple page with an h1 tag to display the page’s name. All the pages that we are going to create will display this information and only. Create a new folder named “Univercity” and add a new Web Form inside it, named “Students.aspx”. Add again an h1 element to display the path and the file name of the new page.

<h1>This is the Univercity/Students.aspx</h1>

By now, your project’s structure should look like this.
web-forms-urlrouting_01
You can request both pages using the default URL Routing system, with the following urls.

http://localhost:your_port/Default.aspx 
http://localhost:your_port/Univercity/Students.aspx

Now let’s create our new routing system. Add a new folder named “App_Start” and create a new C# class “RouteConfig.cs”. This is just a convention we are making, taken from the default MVC structure. Start by adding a RegisterRoutes method. You have to add a using statement for the System.Web.Routing too.

using System.Web.Routing;

namespace AspNetUrlRouting.App_Start
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
        }
    }
}

For any custom virtual path you want to define, you must add a route to the “routes” RouteCollection object. Before adding some virtual paths, let’s first add a Global.asax (Global Application class item) file to our project, and make our new Routing system work.

using AspNetUrlRouting.App_Start;
using System.Web.Routing;

namespace AspNetUrlRouting
{
    public class Global : System.Web.HttpApplication
    {

        protected void Application_Start(object sender, EventArgs e)
        {
            RouteConfig.RegisterRoutes(RouteTable.Routes);
        }
    }
}

Now let’s create our first Fixed routes into the RegisterRoutes function. Assume that we want the Default.aspx page to be indeed the default, which means that if you request http://localhost:your_port/ you want the Default.aspx page to be displayed. At this time, if you do this you will get the following error.
web-forms-urlrouting_02
Make the following addition inside the RegisterRoutes function. Build your project and request the previous URL again.

public static void RegisterRoutes(RouteCollection routes)
        {
            routes.MapPageRoute("default", "", "~/Default.aspx");
        }

web-forms-urlrouting_03
You use the RouteCollection.MapPageRoute to define a new route. It takes three parameters, the route name, the routeURL and the physical file you want to map to.
web-forms-urlrouting_04
Add two fixed URLs that rich the /univercity/Students.aspx page.

public static void RegisterRoutes(RouteCollection routes)
        {
            routes.MapPageRoute("default", "", "~/Default.aspx");
            routes.MapPageRoute("students1", "students", "~/Univercity/Students.aspx");
            routes.MapPageRoute("students2", "univercity/students", "~/Univercity/Students.aspx");
        }

Now the following two URLs will map the Students.aspx page.

http://localhost:your_port/students
http://localhost:your_port/Univercity/Students

web-forms-urlrouting_05
Let’s be honest here, this type of URLs are much more elegant and user friendly than the default “full-path” URLs. Assuming that you wanted all URLs in the form of “{something}/default” match the Default.aspx page, you may think that you have to add dozens of routes in your RegisterRoutes method. This is where variable segments comes into the scene. Adding the following route will make this possible.

public static void RegisterRoutes(RouteCollection routes)
        {
            routes.MapPageRoute("default", "", "~/Default.aspx");
            routes.MapPageRoute("students1", "students", "~/Univercity/Students.aspx");
            routes.MapPageRoute("students2", "univercity/students", "~/Univercity/Students.aspx");
            routes.MapPageRoute("default_all", "{anything}/default", "~/Default.aspx");
        }

web-forms-urlrouting_06
We said previously that the RegisterRoutes method takes three parameters, but that was the simplest method overloading. In fact, there are 5 overloads for this method that supports other URL Routing features. If you are an MVC developer, you will know that you can add constraints to your mapped routes. Let’s modify the last route we added so that the {anything} segment won’t actually match anything but a batch of specified words.

public static void RegisterRoutes(RouteCollection routes)
        {
            routes.MapPageRoute("default", "", "~/Default.aspx");
            routes.MapPageRoute("students1", "students", "~/Univercity/Students.aspx");
            routes.MapPageRoute("students2", "univercity/students", "~/Univercity/Students.aspx");
            //routes.MapPageRoute("default_all", "{anything}/default", "~/Default.aspx");
            routes.MapPageRoute("default_all", "{anything}/default", "~/Default.aspx",
                false, null,
                new RouteValueDictionary { { "anything", "univercity|school|classes" } });
        }

You define constraints by creating a RouteValueDictionary object for a specific segment variable. Here we declared that the {anything} segment can only match 3 specific words, which means that the previous URL will now crash.
web-forms-urlrouting_07
web-forms-urlrouting_08
Last thing I wanna show you, is how to retrieve route values in the code behind file. Add the following route that matches the Students.aspx page and pass an extra integer parameter.

public static void RegisterRoutes(RouteCollection routes)
        {
            routes.MapPageRoute("default", "", "~/Default.aspx");
            routes.MapPageRoute("students1", "students", "~/Univercity/Students.aspx");
            routes.MapPageRoute("students2", "univercity/students", "~/Univercity/Students.aspx");
            //routes.MapPageRoute("default_all", "{anything}/default", "~/Default.aspx");
            routes.MapPageRoute("default_all", "{anything}/default", "~/Default.aspx",
                false, null,
                new RouteValueDictionary { { "anything", "univercity|school|classes" } });
            routes.MapPageRoute("hack_student", "get/students/{id}", "~/Univercity/Students.aspx",
                false, null,
                new RouteValueDictionary { { "id", "[0-9]*" } });
        }

In the code behind file add the following code in the Page_Load event.

public partial class Students : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Route myRoute = RouteData.Route as Route;
            if (myRoute != null && myRoute.Url == "get/students/{id}")
            {
                string id = RouteData.Values["id"].ToString();
                Response.Write("Student: " + id + "<br/>" +
                    "Name: Chris");
            }
        }
    }

Here we get the matched route and if this isn’t null we read it’s routeUrl parameter. If this matches the last added route then we can read the {id} segment value through the “RouteData” object.
web-forms-urlrouting_09
This way you can create the so called Hackable URLs in your Web Forms projects. For example you could have a route like {semester}/students/{id}, read the values in the code behind file and send back the respective values. That’s it, we saw quite valuable concepts on URL Routing on this post that allows you to use user friendly URLs on your web application. You can download the project we built from here. I hope you enjoyed the post!



Categories: ASP.NET

Tags: , ,

6 replies

  1. Very helpful post. Glad to see people still sharing web forms content since there are those of us who will be supporting it for a while to come. 🙂 Again, thank you very much.

  2. Actually no matter if someone doesn’t understand then its up to other
    users that they will assist, so here it takes place.

  3. Very nice article, thank you!

  4. nice artical

  5. A RouteValueDictionary for email address?

Leave a comment