Working with URL Routing in ASP.NET Web Forms

Introduction

While developing web sites, at times you require that the URLs being used are not mapped to any physical file. For example, you might be building a blog engine that stores all blog posts in a SQL Server database but while displaying these posts you want URLs to be SEO friendly. In such cases the resource pointed to by the URL has no physical existence. That's where the URL Routing features of ASP.NET come to the rescue. In addition to creating SEO friendly URLs these features also help you render easy to remember URLs. ASP.NET MVC relies heavily on the URL Routing feature. However, it is also possible to use URL Routing in web forms. In this tutorial you will learn just that.

Sample Scenario

As an example let's assume that you want to build a simple blog engine that renders search engine friendly URLs. To illustrate the use of URL routing in web forms you will build three simple web forms as shown in Figures 1, 2 and 3.

Displaying blog post categories
Figure 1: Displaying blog post categories

The first page, ShowCategories.aspx, lists all the blog post categories in a GridView as shown in Figure 1.

Displaying list of blog posts belonging to a category
Figure 2: Displaying list of blog posts belonging to a category

Upon selecting a particular category from the ShowCategories.aspx page you are taken to ShowPostsByCategory.aspx where all blog posts belonging to that category are displayed in a GridView (Figure 2).

Displaying a blog post
Figure 3: Displaying a blog post

Finally, clicking on a blog post title takes you to ShowPost.aspx (Figure 3) where the complete post is displayed.

In a web site not using URL routing you would have used query string parameters to pass category and blog post information and your URLs would have looked something like this :

/ShowPostsByCategory.aspx?name=jquery

/ShowPost.aspx?postid=10

Using the URL routing feature you will render the URLs as shown below:

/categories/jquery

/2011/06/11/01

Notice and compare the URLs shown above carefully. Instead of passing category name as a query string parameter you will be using it as a part of the URL itself (/categories/jquery). Similarly, instead of passing the blog post ID in the query string you make use of <year>/<month>/<day>/<id> pattern for rendering blog post URLs.

Creating a Sample Database

Let's first create a database for our example. Create a new ASP.NET Empty Web Site and add a new SQL Server database in its App_Data folder. Then create a new table named BlogPosts with schema as shown in Figure 4.

Schema of BlogPosts table
Figure 4: Schema of BlogPosts table

The BlogPosts table has a simple structure (a real world blog will have many more columns but this simplified schema is sufficient for the examples in this article) and consists of five columns viz. Id, Title, Content, PublishDate and Category.

Defining Routes

The first step in using URL routing in web forms is to define one or more routes. A route is a URL pattern that is mapped to a handler. In the case of web forms applications, the handler is an .aspx file. You need to tell ASP.NET what pattern the incoming URL will have and to which .aspx file it should be mapped. You define the routes in the Global.asax file. So, add a Global Application Class (Global.asax) to the web site and write the following code in it:

void Application_Start(object sender, EventArgs e) 
{
    RouteTable.Routes.MapPageRoute("Category", "categories/{name}", "~/ShowPostsByCategory.aspx");
    RouteTable.Routes.MapPageRoute("BlogPost", "posts/{year}/{month}/{day}/{id}", "~/ShowPost.aspx");
}

Here, you handled the Application_Start event and added a couple of route definitions. The URL routing related classes are found in the System.Web.Routing namespace and you should import it at the top of the Global.asax file.

<%@ Import Namespace="System.Web.Routing" %>

The RouteTable class is responsible for storing all the route definitions for a web site. The routes are accessible via the Routes collection. The MapPageRoute() method allows you to map a URL pattern with its handler web form. In the above code, you defined two routes - Category and BlogPost - as indicated by the first parameter of the MapPageRoute() method. The second parameter specifies the URL pattern for a particular route and the last parameter indicates a web form (.aspx) that is going to handle the route. The portion of the URL pattern with { and } is dynamic in nature. The above code maps URLs with pattern categories/{name} to ShowPostsByCategory.aspx and posts/{year}/{month}/{day}/{id} to ShowPost.aspx. For all other URLs ASP.NET will look for a physical resource matching the URL.

Using Route URLs

Now, lets develop the ShowCategories.aspx web form (see Figure 1). Drag and drop an SQL Data Source control and a GridView control on the ShowCategories.aspx. Configure the SQL Data Source control to select unique categories from the BlogPosts table.

Retrieving unique Category values
Figure 5: Retrieving unique Category values

The SQL Data Source control you just configured acts as the data source for the GridView control. Add a single Template Field to the GridView and design the template as per the following markup.

<asp:TemplateField HeaderText="Blog Post Categories">
    <ItemTemplate>
        <asp:HyperLink ID="HyperLink7" runat="server" 
         NavigateUrl='<%# Eval("Category","~/categories/{0}") %>' 
         Text='<%# Eval("Category") %>'>
        </asp:HyperLink>
    </ItemTemplate>
</asp:TemplateField>

Notice how the NavigateUrl property of the HyperLink is set. The URL pattern you used in this case is /categories/{name}.

In our example, the hyperlinks to the categories are generated dynamically. However, if you wish to statically specify route URLs you can also use the following markup:

<asp:HyperLink ID="HyperLink1" runat="server" 

NavigateUrl="<%$RouteUrl:name=jquery,routename=Category %>">jQuery</asp:HyperLink>

Here, you used <%$RouteUrl %> expression to construct the route URLs.

Using Route Parameters with Data Source Controls

In the previous section you developed ShowCategories.aspx. The URLs from ShowCategories.aspx are of the form /categories/{name} and will be handled by ShowPostsByCategory.aspx web form. The ShowPostsByCategory.aspx web form also contains a SQL Data Source control and a GridView control. The SQL Data Source control, in this case, needs to extract the category name passed to the web form in the URL. This is accomplished with the help of a RouteParameter. A route parameter can be added to an SQL Data Source Control in the WHERE clause dialog (Figure 6).

Adding a Route Parameter to SQL Data Source control
Figure 6: Adding a Route Parameter to SQL Data Source control

As you can see, Figure 6 filters the BlogPosts table on the basis of Category column and source of category name is a route parameter named - name. The equivalent markup is shown below:

<asp:SqlDataSource ID="SqlDataSource1" runat="server" 
    ConnectionString="<%$ ConnectionStrings:Database1ConnectionString %>" 
    SelectCommand="SELECT * FROM [BlogPosts] WHERE ([Category] = @Category)">
    <SelectParameters>
        <asp:RouteParameter Name="Category" RouteKey="name" Type="String" />
    </SelectParameters>
</asp:SqlDataSource>

This way the SQL Data Source control will fetch only the blog posts belonging to the category specified in the route URL.

The GridView has a single Template Field as shown below:

<asp:TemplateField HeaderText="Blog Posts By Category">
    <ItemTemplate>
        <asp:HyperLink ID="HyperLink1" runat="server" 
          NavigateUrl='<%# GetUrl(Eval("Id"),Eval("PublishDate")) %>' 
          Text='<%# Eval("Title") %>'>
        </asp:HyperLink>
    </ItemTemplate>
</asp:TemplateField>

Notice how the NavigateUrl property of the HyperLink is set. It passes the Id and PublishDate values to GetUrl() method. The GetUrl() method then forms a URL as per the required pattern (posts/{year}/{month}/{day}/{id}) and assigns it to the NavigateUrl property. The GetUrl() method is shown next.

protected string GetUrl(object id, object pubDate)
{
    DateTime dt = DateTime.Parse(pubDate.ToString());
    int postId = int.Parse(id.ToString());
    RouteValueDictionary parameters = new RouteValueDictionary 
    { { "year", dt.Year }, { "month", dt.Month }, { "day", dt.Day }, { "id", postId } };
    return Page.GetRouteUrl("BlogPost",parameters);
}

The GetUrl() method first converts the supplied Id and PublishDate from object to integer and DateTime data types respectively. It then creates a RouteValueDictionary with all the route parameters. In this case route parameters are - year, month, day and id. The GetRouteUrl() method of the Page object accepts a route name and its parameters and returns the corresponding URL (e.g. /posts/2010/12/15/1).

Accessing Route Parameter Values

In this final section you will develop ShowPost.aspx - the web form that displays a particular blog post. This web form needs to access year, month, day and id route parameters and then fetch a blog post based on them.

Drag and drop three Literal controls on the web form and write the following code in the Page_Load event handler.

protected void Page_Load(object sender, EventArgs e)
{
    int year = Convert.ToInt32(Page.RouteData.Values["year"]);
    int month= Convert.ToInt32(Page.RouteData.Values["month"]);
    int day = Convert.ToInt32(Page.RouteData.Values["day"]);
    int id = Convert.ToInt32(Page.RouteData.Values["id"]);

    DateTime dt = new DateTime(year, month, day);

    DataClassesDataContext db=new DataClassesDataContext();

    var record = from p in db.BlogPosts
                 where p.PublishDate == dt && p.Id ==id 
                 select p;

    foreach (BlogPost temp in record)
    {
        Literal1.Text = "<h1>" + temp.Title + "</h1>";
        Literal2.Text = temp.Content;
        Literal3.Text = "Published on : " + temp.PublishDate.ToString();
    }

}

Notice how the above code retrieves route parameters via the RouteData object. The RouteData object stores values as objects and you need to convert them to the appropriate data type. Based on the year, month and day values a DateTime instance is constructed. A LINQ to SQL query is then executed (you need to add a LINQ to SQL class for the BlogPosts table or else you can also write ADO.NET code yourself) to fetch a blog post for that PublishDate and Id (actually you could have used just the Id value as it is the primary key but just to illustrate the use of all route parameters we are using both the conditions). Finally, the blog post is displayed in the Literal controls.

Once the web forms are developed, run ShowCategories.aspx and navigate to a category. Then pick one blog post and see if it is displayed correctly. Notice the URL pattern in each web form and see how URL routing is mapping the URLs with web forms.

Summary

ASP.NET URL Routing features allow you to use URLs that are not directly mapped to a physical file. A route is a URL pattern that is mapped to a handler such as an .aspx file. You can use the URL routing feature in a web forms application by defining one or more routes in Global.asax and then using classes from System.Web.Routing namespace. The data source controls offer Route Parameters to filter data based on route parameter values. The route URLs can be put statically using RouteUrl expression or programmatically using GetRouteUrl() method. A web form can access route parameters with the help of the RouteData object. Together these features make it easy for you to use search engine friendly and easy to remember URLs in your web form based web sites.



About the Author

Bipin Joshi

Bipin Joshi is a blogger and writes about apparently unrelated topics - Yoga & technology! A former Software Consultant by profession, Bipin has been programming since 1995 and has been working with the .NET framework ever since its inception. He has authored or co-authored half a dozen books and numerous articles on .NET technologies. He has also penned a few books on Yoga. He was a well known technology author, trainer and an active member of Microsoft developer community before he decided to take a backseat from the mainstream IT circle and dedicate himself completely to spiritual path. Having embraced Yoga way of life he now codes for fun and writes on his blogs. He can also be reached there.

Related Articles

Downloads