RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Design Patterns for ASP.NET Developers, Part 2: Custom Controller Patterns : Page 5

If any part of your ASP.NET applications display pages based on user interaction, browser type, security permissions, or other factors, you'll find these Controller patterns useful.

Implementing the Front Controller Pattern
The most common approach for implementing the Front Controller pattern in ASP.NET is through an HTTP Module that handles one of the ASP.NET HTTP pipeline events, and executes a Server.Transfer action to load the appropriate target page. This is the technique implemented in the example application. A dropdown list at the bottom of the Default.aspx page displays a list of possible targets, from which you can select (see Figure 8).

Figure 8. Sample Application Page Targets: The figure shows the list of targets for the Front Controller example displayed in the default page.
You may recall from the discussion of the Singleton pattern in the previous article in this series that the example application uses a Singleton class named TransferUrlList.cs to expose the contents of an XML file that contains the target "short names" (as displayed in the dropdown list in Figure 8) and the actual URL to load:

   <?xml version="1.0" encoding="utf-8" ?>
     <item name="UseCaseController" url="TransferPage1.aspx" />
     <item name="CustomerList" 
       url="TransferPage2.aspx?view=CustomerList" />
     <item name="CustomerDetails" 
       url="TransferPage2.aspx?view=CustomerDetails" />
     <item name="CityList" 
       url="TransferPage2.aspx?view=CityList" />
     <item name="SpecialCustomerList" 
       url="TransferPage3.aspx?view=CustomerList" />
     <item name="SpecialCustomerDetails" 
       url="TransferPage3.aspx?view=CustomerDetails" />
     <item name="SpecialCityList" 
       url="TransferPage3.aspx?view=CityList" />
     <item name="Publish-Subscribe" url="TransferPage4.aspx" />
     <item name="Command-Observer" url="TransferPage5.aspx" />
To demonstrate the Front Controller pattern, the application contains a class named FrontController.cs (in the App_Code folder) that implements an HTTP Module. The class declaration indicates that it implements the IHttpModule interface, which means that it must declare the public methods Init and Dispose.

In the Init method, the class subscribes to the PreRequestHandlerExecute event by registering an event handler named MyPreRequestHandler. As the class does not use any unmanaged resources, the Dispose method requires no action—so it declares only an empty method:

   public class FrontController : IHttpModule
      public void Init(HttpApplication context)
         // register a handler for the event you want to handle
         context.PreRequestHandlerExecute += MyPreRequestHandler;
      public void Dispose()
         // no clean-up required
The ASP.NET HTTP pipeline raises the PreRequestHandlerExecute event just before it executes the request. The code in the event handler in the FrontController module can therefore make a decision about which page to load based on some external condition. This may be something like the browser language, country, browser type, a value in the user's ASP.NET Profile, or some other value from the environment.

The example module takes simpler approach to make it easier to specify the target you want when experimenting with the application. It examines the query string for a value that corresponds to one in the list of transfer URLs exposed from the XML file, and redirects to the appropriate page. The GetTransferUrl method of the TransferUrlList class returns the translated URL if found in the list, or the original URL if it is not in the list. The code then executes the Server.Transfer method to that URL:

   private void MyPreRequestHandler(Object sender, EventArgs e)
      // use features of the request (user, browser, 
      // IP address, etc.) to decide how to handle the request, 
      // and which page to show.
      // this example looks for specific items in the query 
      // string that indicate the required target (such as 
      // "CustomerList") using a dictionary of values loaded from 
      // an XML disk file
      // get Singleton list of transfer URLs 
      TransferUrlList urlList = TransferUrlList.GetInstance();
      // get the current request query string
      String reqTarget = HttpContext.Current.
      if (reqTarget!= null && reqTarget != String.Empty)
         // see if target value matches a transfer URL
         // by querying the list of transfer URLs
         // method returns the original value if no match 
         String transferTo = urlList.GetTransferUrl(reqTarget);
            // transfer to the specified URL
            HttpContext.Current.Server.Transfer(transferTo, true);
Figure 9. Effect of Selecting "CustomerDetails": When you select the "CustomerDetails" item in the dropdown list, the application loads TransferPage2, which displays the CustomerDetails View as shown here.
catch { } } }
When you select one of the "short name" values in the dropdown list in the default page of the application, you'll see the effects of the Front Controller module. For example, Figure 9 shows the result of selecting the "CustomerDetails" option. The code in the Front Controller HTTP module translates this into the URL TransferPage2.aspx?view=CustomerDetails—as you can see in the Label control that displays the actual URL of the current page.

Notes on Using a Front Controller HTTP Module
You may be tempted to try using URLs for your Front Controller that include the "short names" as part of the path, rather than in the query string. This will work when you run your application within Visual Studio 2005 because all requests go to the built-in Visual Studio Web server. However, if you run your application under the IIS Web server you will get "Page Not Found" errors, because IIS passes only pages that actually exist to the ASP.NET runtime.

For example, if you use a URL such as http://localhost/CityList, and there is no folder in your Web site named CityList, IIS will return a "404 Not Found" error. It will not initiate the ASP.NET HTTP pipeline, and so your module will not execute. Even if the CityList folder does exist, IIS will return either a "403 - Forbidden" error, or (if Directory Browsing is enabled) a file listing.

Of course, you could create a folder for each "short name" and put an empty ASPX page in each of these folders so that the Front Controller module redirects to the appropriate page as required. This is better than using pages that contain redirection code (such as Response.Redirect or <meta httpequiv="refresh"> elements) in each folder, because the Front Controller will intercept each request and will not actually load the empty ASP.NET page.

An alternative is to map all requests to the ASP.NET runtime DLL, rather than just the standard ASP.NET file extensions such as aspx and ascx. However, this is probably not a practical solution because it will result in an excessive processing overhead in ASP.NET.

As you are probably beginning to realize, ASP.NET makes extensive use of design patterns internally, and you can capitalize on design patterns yourself to build logical and easy-to-maintain applications. I'll cover some more advanced patterns in the final article in this series.

Alex Homer is a director of Stonebroom, Ltd., a software development, consulting, and training organization. He was formerly lead technical author and reviewer for Wrox, specializing in Microsoft Web and database technologies. You can reach him through his Web site.
Email AuthorEmail Author
Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date