Chapter 24. Advanced Navigation

Websites tend to be organic—they grow and change over time. This can create problems when other applications link to your application. You need some way of modifying your website without breaking all the existing links to your website.

In this chapter, you learn how to remap URLs. In other words, you learn how to serve a different page than the page a user requests. In the first section of the chapter, you learn how to remap URLs in the web configuration file.

Next, you learn how to remap URLs by creating a custom HTTP module. Using a module is useful when you need to support wildcard matches and other types of pattern matching when remapping a URL.

Finally, you learn how to use the VirtualPathProvider class to remap URLs. You learn how you can store all your website pages in a database. In the last section of this chapter, a simple Content Management System (CMS) is built with the VirtualPathProvider class.

All these techniques are different than the techniques that use the new ASP.NET 4 Routing Engine. If your goal is to provide “permalink” type functionality or specifically map URLs to pieces of content (rather than .aspx pages), these techniques are for you. However, if your goal is to provide a more SEO-friendly, user-friendly, and possibly REST-friendly URL pattern for your entire website, you should not use the techniques in this chapter and instead skip to the chapter on the URL Routing Engine.

Remapping URLs

The simplest way to remap a URL is to specify the remapping in your application’s web configuration file. For example, the web configuration file in Listing 24.1 remaps the Home.aspx page to the Default.aspx page.

Listing 24.1. Web.Config

images

The configuration file in Listing 24.1 contains a <urlMappings> element. This element can contain one or more elements that remap a page from a URL to a mapped Url.

The mappedUrl attribute can contain query strings. However, it cannot contain wildcards. You can use the <urlMappings> element only when performing simple page-to-page mappings.

After you add the web configuration file in Listing 24.1 to your application, any requests for the Home.aspx page are modified automatically to requests for the Default.aspx page. It doesn’t matter whether the Home.aspx page actually exists. If the Home.aspx page does exist, you can never open the page.

Note

The tilde character (~) has a special meaning when used with a path. It represents the current application root. A forward slash (/) at the start of a URL, on the other hand, represents the website root.

You can use the tilde only with properties of ASP.NET controls. For example, you can use it with the ASP.NET Image control’s ImageUrl property, but you cannot use it with the HTML <img> src attribute.

In code, you can use the tilde character with a path by using the Page.ResolveUrl() method. This method automatically expands the tilde to the application root.

When working with remapped URLs, you often need to determine the original URL that a user requested. For example, you might want to display a message that tells users to update their bookmarks (favorites) to point to the new URL.

You can use the following to determine the current URL:

Request.RawUrlReturns the original URL (before being remapped).

Request.PathReturns the current URL (after being remapped).

Request.AppRelativeCurrentExecutionFilePathReturns the application relative URL (after being remapped).

The last property automatically replaces the name of the web application with a tilde (~) character.

For example, the Default.aspx page in Listing 24.2 illustrates all three properties.

Listing 24.2. Default.aspx

images

images

If you request the Home.aspx page, the request is remapped to the Default.aspx page by the web configuration file in Listing 24.1. The Page_Load() event handler displays a message asking users to update their bookmarks when the RawUrl does not match the path (see Figure 24.1).

Figure 24.1. Remapping the Home page.

image

Each property displayed in the body of the page displays a different value:

image

Creating a Custom UrlRemapper Module

The <urlMappings> configuration element discussed in the previous section performs a simple task. It remaps one page to another. However, you quickly discover that you need to perform more complex remappings.

For example, imagine that you have a database that contains a table of product categories and a table of products. You want your website’s users to request a URL that contains a product category and to see matching products. For example, if someone requests the /Products/Soda.aspx page, you want to display all the products in the Soda category. If someone requests the /Products/Milk.aspx page, you want to display all the products in the Milk category.

In that case, you need to use a wildcard when matching URLs. When someone requests any path that matches the pattern /Products/*, you want to redirect the user to a page where you can display matching products for the category specified in the path.

In this section, we create a custom HTTP module that remaps one URL to another. The module supports regular expression matching. Therefore it supports wildcard matches.

The code for the custom module—named UrlRemapper—is contained in Listing 24.3.

Listing 24.3. UrlRemapper.cs

images

images

The class in Listing 24.3 implements the IHttpModule interface. An HTTP module is a special class that executes whenever you make a page request. HTTP Modules are discussed in detail in Chapter 31, “Working with the HTTP Runtime.”

The module in Listing 24.3 includes an Init() method. This method adds an event handler for the Application BeginRequest event. The BeginRequest event is the first event raised when you request a page.

The BeginRequest handler gets a list of URL remappings from an XML file named UrlMappings.config. The contents of this XML file are cached in memory until the UrlMappings.config file is changed on the hard drive.

Next, the module iterates through each remapping from the XML file and performs a regular expression match against the current URL. If the match is successful, the Context.RewritePath() method is used to change the current path to the remapped path.

Before you can use the module in Listing 24.3 in an application, you must first register the module in your application’s web configuration file. The web configuration file in Listing 24.4 contains an <httpModules> element that includes the UrlRemapper module.

Listing 24.4. Web.Config

images

A sample UrlMappings.config file is contained in Listing 24.5.

Listing 24.5. UrlMappings.config

images

The XML file in Listing 24.5 contains two remappings. First, it remaps any request for the Home.aspx page to the Default.aspx page. Second, it remaps any request for any page in the Products directory to the Default.aspx page located in the Products folder.

The second mapping uses a regular expression to match the incoming URL. The .* expression matches any sequence of characters.

The Default.aspx page in the Products folder is contained in Listing 24.6.

Listing 24.6. Products/Default.aspx

images

images

images

The Page_Load() event handler in Listing 24.6 grabs the path of the original request, using the Request.RawUrl property. Next, it extracts the filename from the path, using the System.IO.Path.GetFileNameWithoutExtension() method. Finally, it assigns the name of the page (the category name) to a Label and SqlDataSource control. Products that match the category display in a GridView control.

For example, if you request the /Products/Soda.aspx page, all the products in the Soda category display (see Figure 24.2). If you request the /Products/Milk.aspx page, all products in the Milk category display.

Figure 24.2. Displaying matching products.

image

Using the VirtualPathProvider Class

The VirtualPathProvider class enables you to abstract the pages in a web application from the file system. In other words, it enables you to store your ASP.NET pages any way you please.

For example, you can use the VirtualPathProvider class to store all the pages in your application in a database. This would be an appropriate choice when you need to build a Content Management System. If you store pages in a database, users can update the pages easily in an application through an HTML form interface and save the changes to the database.

In this section, we present you with some basic information about the VirtualPathProvider class. We do not go into too much detail or provide a lengthy code example because for many modern scenarios you probably want to use the new Routing Engine rather than the VPP. The VPP is ideal if you want to take specific URLs and provide access to underlying content (rather than invoke ASPx pages). If you want nice URLs that invoke ASPx pages, your best bet is to use the new routing engine.

Limitations of the VirtualPathProvider Class

Unfortunately, you can’t use the VirtualPathProvider with every type of file. In particular, the following types of files must always be located on the file system:

Global.asax file

Web.Config files

• App_Data folder

• App_Code folder

• App_GlobalResources folder

• App_LocalResource folders

• Bin folder

Every other type of file is fair game. This includes ASP.NET pages, User controls, Themes, and Master Pages.

Understanding the VirtualPathProvider Class

The VirtualPathProvider class is a MustInherit (abstract) class. It contains the following methods, which you can override:

CombineVirtualPaths()Returns a combined path from two paths.

DirectoryExists()Returns true when a directory exists.

FileExists()Returns true when a file exists.

GetCacheDependency()Returns a cache dependency object that indicates when a file has been changed.

GetCacheKey()Returns the key used by the cache dependency.

GetDirectory()Returns a VirtualDirectory.

GetFile()Returns a VirtualFile.

GetFileHash()Returns a hash of the files used by the cache dependency.

OpenFile()Returns the contents of a file.

Typically, you override the FileExists() and GetFile() methods to retrieve a file from your data store. If you want to represent directories, you also need to override the DirectoryExists() and GetDirectory() methods.

Several of these methods are related to caching. The VirtualPathProvider needs to know when a file has been modified so that it can retrieve the new version of the file and compile it. By default, the ASP.NET Framework uses a file dependency to determine when a file has been modified on the hard drive. However, in this situation a SqlCacheDependency is used because the files will be stored in a database.

The VirtualPathProvider also includes a useful property:

PreviousReturns the previously registered VirtualPathProvider.

The Previous property enables you to use the default VirtualPathProvider. For example, if you want to store some files in the file system and other files in the database, you can use the Previous property to avoid rewriting all the logic for working with files in the file system.

The GetFile() method returns an instance of the VirtualFile class. When using the VirtualPathProvider, you must create a new class that inherits from the VirtualFile class. This class contains the following properties:

IsDirectoryAlways returns False.

NameReturns the name of the file.

VirtualPathReturns the virtual path of the file.

The VirtualFile class also contains the following method:

Open()Returns the contents of the file.

Typically, when creating a class that inherits from the VirtualFile class, you override the Open() method. For example, we override this method to get the contents of a file from a database table in the code sample built in this section.

The GetDirectory() method returns an instance of the VirtualDirectory class. This class contains the following properties:

ChildrenReturns all the files and directories that are children of the current directory.

DirectoriesReturns all the directories that are children of the current directory.

FilesReturns all the files that are children of the current directory.

IsDirectoryAlways returns True.

NameReturns the name of the directory.

VirtualPathReturns the virtual path of the directory.

There is another class in the ASP.NET Framework that you want to use when working with the VirtualPathProvider class. The VirtualPathUtility class contains several useful methods for working with virtual paths:

AppendTrailingSlash()Returns a path with at most one forward slash appended to the end of the path.

Combine()Returns the combination of two virtual paths.

GetDirectory()Returns the directory portion of a path.

GetExtension()Returns the file extension of a path.

GetFileName()Returns the filename from a path.

IsAbsolute()Returns True when a path starts with a forward slash.

IsAppRelative()Returns True when a path starts with a tilde (~).

MakeRelative()Returns a relative path from an application-relative path.

RemoveTrailingSlash()Removes trailing slash from the end of a path.

ToAbsolute()Returns a path that starts with a forward slash.

ToAppRelative()Returns a path that starts with a tilde (~).

By taking advantage of the VirtualPathUtility class, you can avoid doing a lot of tedious string parsing on paths.

Registering a VirtualPathProvider Class

Before you can use an instance of the VirtualPathProvider class, you must register it for your application. You can register a VirtualPathProvider instance with the HostingEnvironment.RegisterVirtualPathProvider() method.

You need to register the VirtualPathProvider when an application first initializes. You can do this by creating a shared method named AppInitialize() and adding the method to any class contained in the App_Code folder. The AppInitialize() method is automatically called by the ASP.NET Framework when an application starts.

For example, the following AppInitialize method registers a VirtualPathProvider named MyVirtualPathProvider:

image

Summary

This chapter explored several advanced topics related to website navigation. In the first two sections, you learned how to map URLs from one path to another. In the first section, you learned how to configure remappings in the Web configuration file. In the second section, you learned how to build a custom HTTP module, which enables you to use wildcard matches when remapping a URL.

In the final section of this chapter, you learned how to abstract pages in your application from the file system by using the VirtualPathProvider class. The techniques described in this chapter remain in this book mostly for backward compatibility with previous versions of ASP.NET. They still work in ASP.NET 4, but you might want to consider using the new Routing Engine if your goal is to provide powerful, flexible URL schemes that still invoke underlying ASPx pages. If you are simply pointing one location to another, or providing a URL scheme on top of nonexecutable content files, this chapter still applies to your situation.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset