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