A Look at ASP.NET 2.0's URL Mapping

Introduction
URL mapping - a feature new to ASP.NET 2.0 - enables page developers to map one set of URLs to another. If a request comes in for one of the URLs in the first set, it is automatically re-mapped on the server-side. For example, you can configure the application so that the URL ~/Beverages.aspx is mapped to ~/ProductsByCategory.aspx?CategoryID=1&CategoryName=Beverages. With such a mapping in place, when a user enters http://YourSite.com/Beverages.aspx into their browser's Address bar, on the server-side the request will be handled as if they had entered http://YourSite.com/ProductsByCategory.aspx?CategoryID=1&CategoryName=Beverages. The user, however, will continue to see http://YourSite.com/Beverages.aspx in their browser's Address bar; they won't know that the request was re-mapped.

URL mapping is often used to provide "friendly" URLs, which are URLs that are more readable and sensical - Beverages.aspx is a "friendly" URL as it is more readable than ProductsByCategory.aspx?CategoryID=1&CategoryName=Beverages. URL mapping also is useful when restructuring a site. Imagine that all product information was accessible through http://YourSite.com/Products/..., but the higher-ups want the products rooted available through http://YourSite.com/Catalog/... instead. Clearly, any users who have the old links bookmarked or linked from a website will get 404s if they visit once the folder name change has been made. This can be mitigated by using URL mapping to map each page in the Products folder to its corresponding page in Catalog.

In this article we'll explore how to configure an ASP.NET 2.0 web application to provide URL mappings as well as look at how URL mappings work underneath the covers. We'll also discuss techniques for implementing URL mapping in ASP.NET version 1.x along with ideas for extending ASP.NET 2.0's URL mapping feature. Read on to learn more!

Defining URL Mappings
The URL mapping feature in ASP.NET 2.0 is very simple and works by specifying the mapping directly in Web.config. This simplicity makes it easy to setup and configure, but renders the built-in mapping capabilities impotent for more complex scenarios, where the mapping rules need to be dynamically defined or there needs to be greater flexibility in the mapping. We'll address the downside of this simplicity later on in this article.

To specify the mappings, simply add a <urlMappings> element to Web.config. Set the enabled attribute to true and then include an <add> element for each mapping. In the <add> element, specify the incoming URL to look for and the URL to map it to using the url and mappedUrl attributes, respectively.

The download available at the end of this article provides an ASP.NET 2.0 web application that uses the Northwind database to display information about products. There's a page, ProductsByCategory.aspx that expects two querystring parameters: CategoryID and CategoryName. The page then displays the passed-in CategoryName value in a Label Web control and uses a GridView and SqlDataSource control to display the specified CategoryID's products. Therefore, to view the products in the Beverages category, a user would visit ~/ProductsByCategory.aspx?CategoryID=1&CategoryName=Beverages.

We can use ASP.NET 2.0's URL mapping feature to provide a friendly URL, like ~/Beverages.aspx. The following <urlMappings> element markup provides eight mappings, creating a friendly URL for each of the categories in the Northwind database's Categories table. With these mappings in place, a user can view the products in the Beverages category by visiting either ~/ProductsByCategory.aspx?CategoryID=1&CategoryName=Beverages or ~/Beverages.aspx.

<configuration>
   ...
   <system.web>
    ...
    
    <urlMappings enabled="true">
     <add
        url="~/Beverages.aspx"
        mappedUrl="~/ProductsByCategory.aspx?CategoryID=1&amp;CategoryName=Beverages" />
     <add
        url="~/Condiments.aspx"
        mappedUrl="~/ProductsByCategory.aspx?CategoryID=2&amp;CategoryName=Condiments" />
     <add
        url="~/Confections.aspx"
        mappedUrl="~/ProductsByCategory.aspx?CategoryID=3&amp;CategoryName=Confections" />
     <add
        url="~/Dairy.aspx"
        mappedUrl="~/ProductsByCategory.aspx?CategoryID=4&amp;CategoryName=Dairy+Products" />
     <add
        url="~/Grains.aspx"
        mappedUrl="~/ProductsByCategory.aspx?CategoryID=5&amp;CategoryName=Grains+and+Cereals" />
     <add
        url="~/Meat.aspx"
        mappedUrl="~/ProductsByCategory.aspx?CategoryID=6&amp;CategoryName=Meat+and+Poultry" />
     <add
        url="~/Produce.aspx"
        mappedUrl="~/ProductsByCategory.aspx?CategoryID=7&amp;CategoryName=Produce" />
     <add
        url="~/Seafood.aspx"
        mappedUrl="~/ProductsByCategory.aspx?CategoryID=8&amp;CategoryName=Seafood" />
    </urlMappings>
   </system.web>
</configuration>

Note: Since the markup in Web.config is XML, it is important that reserved characters be escaped. The ampersand character (&), for example, should be escaped using &amp;, as the URLs in the mappedUrl attributes show.

Even when the page is visited through the friendly URL (Beverages.aspx), the querystring parameters from the mapped URL are available. The screenshot below illustrates this. Note that the user has entered into the browser Beverages.aspx. When the request enters the server, it re-maps it to ~/ProductsByCategory.aspx?CategoryID=1&CategoryName=Beverages, but the user keeps seeing Beverages.aspx in the browser's Address bar. But from the perspective of the server-side code, the querystring parameters CategoryID and CategoryName are present and are used in displaying the category's name and its products.

The friendly URL Beverages.aspx is mapped to the lengthy URL.

How ASP.NET 2.0 Re-Maps URLs
When a request reaches the web server, it passes through a series of steps en route to being rendered. After proceeding through these steps, the ASP.NET runtime determines the requested URL, grabs that page's corresponding class, and instructs the class to render itself. The page goes through its lifecycle, which includes initializing its control hierarchy and progressing through a number of stages - PreInit, Init, Load, and so forth - with the net result being the page is rendered into markup. This markup is then returned to the requesting browser and displayed.

One of the steps that occurs before the page is rendered examines the requested URL and checks to see if there are any matching URL mappings. If there are, it uses the HttpContext class's RewritePath method. This method updates the current request's URL to the one specified by the mapping rule in Web.config. With this information updated, when the page is ready to be rendered, the system sees that it's supposed to render the mapped page, and uses that URL instead of the one initially requested by the user. The net result is that the mapped page is rendered, but the user (and their browser) thinks that they are visiting the page they requested.

The following diagram illustrates this workflow:

The URL mapping workflow.

Shortcomings of ASP.NET 2.0's URL Mapping
There are two major shortcomings of ASP.NET 2.0's built-in URL mapping feature. First, it requires that the URL mappings be statically defined in Web.config. This is less than ideal for data-driven websites that use friendly URLs because it means someone has to manually enter the friendly URLs rather than having them read from the database dynamically. With the download at the end of this tutorial, for example, if you delete a category from the database or add a new one, you'll have to manually go to Web.config and add or remove an <add> element to the <urlMappings> section.

The other major shortcoming is the lack of regular expression support. Rather than having to hard-code all URLs, in many situations it is useful to be able to define a mapping pattern. This is especially helpful if using URL mapping to prevent broken URLs after a site restructuring. With the ability to use regular expressions in the rewriting rules, the following single mapping would map all requests to the Old folder to the same name in the New folder. (The assumption here being that the site was restructured and the Old folder was renamed to New.)

<add url="~/Old/(.*)" mappedUrl="~/New/$1" />

While ASP.NET 2.0 doesn't support regular expressions in its URL mapping implementation, Chris Pietschmann provides the code for an HTTP Module that does this in his blog entry ASP.NET 2.0: URL Mapping with RegEx Support. This HTTP Module could be extended to support dynamic mapping rules, as well.

Another, less impactful shortcoming is that a page visited through URL mapping has its <form>'s action element reference the actual, underlying page. That is, if a user visits the friendly URL Beverages.aspx, which maps to ProductsByCategory.aspx?CategoryID=1&CategoryName=Beverages, when the page is posted back the user's browser will request ProductsByCategory.aspx?CategoryID=1&CategoryName=Beverages and not Beverages.aspx. Things will function normally, but the URL in the Address bar will change after the first postback, which may be a triffle confusing to users who are noting the URL.

URL Mapping in ASP.NET 1.x
ASP.NET version 1.x does not support the <urlMappings> element like in ASP.NET 2.0, but URL mapping is possible through a custom HTTP Handler or Module. Rather than detail the process here, let me refer you to a previous article of mine on the topic: URL Rewriting in ASP.NET. This article was written for ASP.NET 1.x, but the concepts apply to ASP.NET 2.0 as well. Chris Pietschmann's HTTP Module for ASP.NET 2.0 mapping with regular expression support uses the same concepts.

The URL Rewriting in ASP.NET also looks at a technique for having a re-mapped page's form's action attribute use the friendly URL rather than the underlying page's URL.

Conclusion
In this article we looked at ASP.NET 2.0's URL mapping feature, which provides a simple way to define a mapping from one set of URLs to another. This technique is commonly used to create "friendly" URLs or to handle potentially disruptive site restructurings. Unfortunately, the built-in URL mapping features are overly simplistic and don't provide the features commonly needed in real-world scenarios. It is possible to provide such functionality, though, through a custom HTTP Module. IIS 7 is slated to include a greater degree of rewriting capabilities.

Happy Programming!

  • By Scott Mitchell


    Attachments

  • Download the code used in this article

    Further Readings

  • ASP.NET URL Mapping (from the ASP.NET 2.0 QuickStarts)
  • ASP.NET 2.0: URL Mapping with RegEx Support
  • URL Rewriting in ASP.NET (an article written for ASP.NET 1.x, but the concepts pertain to ASP.NET 2.0 as well)
  • posted on 2008-10-20 21:40  starspace  阅读(289)  评论(0编辑  收藏  举报

    导航