Sanibel Logic LLC

...Scalable Technologiesfor the Enterprise

Exporting System Event Log

When trouble shooting WebKeepAlive problems, you may be asked to export and email the System Application Event Log.  To do so, proceed to the Windows Control Panel, then click on Administrative Tools and then click on the Event Viewer, as illustrated below with Windows Server 2003.  Highlight the Application event log, right click the mouse and then click on Save Log File As

EventLog-Export

Once the Save "Application" As  dialog window appears, provide a file name and .evt  file extension.  Be sure to compress the file first in ZIP form before emailing.

EventLog Export SaveAs

Exporting WebKeepAlive Registry Definitions

When one uses the WebKeepAlive Configuration program to add URLs and define the overall WebKeepAlive environment, all definitions are retained within the System Registry.  When trouble shooting problems, you may be asked to export the WebKeepAlive Registry contents.  To do so, execute the following instructions and email the saved file to Sanibel Logic support.

After bringing up a command prompt window, key in REGEDIT.

RegEdit Command Prompt

A GUI Registry Editor window will appear.  Navigate and click on the HKEY_LOCAL_MACHINE\SOFTWARE\Sanibel Logic\WebKeepAliveV5 registry key.  Right click the mouse and select Export.

RegEdit Export

Once the SaveAs dialog window appears, as illustrated below, provide a file name and .reg  file extension.  Be sure to compress the file first in ZIP form before emailing.

RegEdit Export SaveAs

ListView ItemTemplate and AlternatingItemTemplate

The ASP.NET 3.5 ListView server control provides an ItemTemplate and an AlternatingItemTemplate.  Only the ItemTemplate is required for defining each row's content.  The AlternatingItemTemplate can be used to define row content for odd numbered rows, however quite often the even and odd rows are identical with the exception that a different CSS class definition needs to be used, so to provide a different visible experience to the user.  Rather than duplicate the bulk of the ItemTemplate into the AlternatingItemTemplate, one can provide inline code to examine the container's row number and return a specific even or odd CSS class name, illustrated as follows:

   1:  <asp:ListView ID="listViewSort" 
   2:      DataSourceID="ObjMenu" 
   3:      DataKeyNames="Name"
   4:      runat="server">
   5:      <LayoutTemplate>
   6:          <table runat="server" 
   7:              class="listViewGrid"
   8:              cellspacing="0"
   9:              border="0">
  10:              
  11:              <tr runat="server" id="itemPlaceholder" />
  12:          
  13:          </table>    
  14:      </LayoutTemplate>
  15:      <ItemTemplate>
  16:          <tr class="<%# ((ListViewDataItem)Container).DisplayIndex % 2 == 0 ? "itemRow" : "altItemRow" %>">
  17:              <td align="left" style="width: 200px;">
  18:                  <asp:Label runat="server" 
  19:                      Text='<%# Eval("Name") %>' />
  20:              </td>
  21:              <td align="right" style="width: 100px;">   
  22:                  <asp:Label runat="server" 
  23:                      Text='<%# Eval("Price") %>' />
  24:              </td>
  25:              <td align="left" style="width: 400px;">
  26:                  <asp:Label runat="server" 
  27:                      Text='<%# Eval("Description") %>' />
  28:              </td>
  29:              <td align="right" style="width: 100px;">
  30:                  <asp:Label runat="server" 
  31:                      Text='<%# Eval("Calories") %>' />
  32:              </td>
  33:          </tr>
  34:      </ItemTemplate>
  35:  </asp:ListView>    

If the inline processing is more complicated than one would prefer for inline code, then one can invoke a protected web page method to accomplish similar or more complicated tasks, illustrated as follows:

   1:  <asp:ListView ID="listViewSort" 
   2:      DataSourceID="ObjMenu" 
   3:      DataKeyNames="Name"
   4:      runat="server">
   5:      <LayoutTemplate>
   6:          <table runat="server" 
   7:              class="listViewGrid"
   8:              cellspacing="0"
   9:              border="0">
  10:              
  11:              <tr runat="server" id="itemPlaceholder" />
  12:          
  13:          </table>
  14:      </LayoutTemplate>
  15:      <ItemTemplate>
  16:          <tr class="<%# GetCssName(Container) %>">
  17:              <td align="left" style="width: 200px;">
  18:                  <asp:Label runat="server" 
  19:                      Text='<%# Eval("Name") %>' />
  20:              </td>
  21:              <td align="right" style="width: 100px;">   
  22:                  <asp:Label runat="server" 
  23:                      Text='<%# Eval("Price") %>' />
  24:              </td>
  25:              <td align="left" style="width: 400px;">
  26:                  <asp:Label runat="server" 
  27:                      Text='<%# Eval("Description") %>' />
  28:              </td>
  29:              <td align="right" style="width: 100px;">
  30:                  <asp:Label runat="server" 
  31:                      Text='<%# Eval("Calories") %>' />
  32:              </td>
  33:          </tr>
  34:      </ItemTemplate>
  35:  </asp:ListView>    

The protected web page method in turn can provide simple or more complex logic.  In this illustration, the same logic is provided as the inline code example:

   1:  protected string GetCssName(object container)
   2:  {
   3:      if (container != null)
   4:      {
   5:          if (container.GetType() == typeof(ListViewDataItem))
   6:          {
   7:              if ((((ListViewDataItem)container).DisplayIndex % 2) == 0)
   8:              {
   9:                  return "itemRow";
  10:              }
  11:              else
  12:              {
  13:                  return "altItemRow";
  14:              }
  15:          }
  16:      }
  17:      return null;
  18:  }

 

While the ListView server control AlternatingItemTemplate is quite useful, its use should be limited to instances where there is truly differing content requirements between even and odd numbered rows.  The above illustrations also works equally as well with my previously posted ListViewSort custom control.

Obtain Client Browser Time Zone

Sanibel Logic is offering a free download which may be useful for your software development.  ClientTime is an ASP.NET custom control based on an article entitled "Its About Time" in the January 2007 issue of ASP.NetPro magazine.  The ASP.NetPro article discusses the JavaScript requirements for obtaining the client browser time zone. I take the article a step further by encapsulating C# support methods and JavaScript injection code into the form of an ASP.NET custom control.  ClientTime can be useful for ASP.NET based web applications to ensure that all Date/Times are expressed in the client browser's time zone.

To illustrate, the following Administrative query which monitors ASP.NET Health Monitoring alerts shows all date and times (highlighted within red block) expressed in the local time zone of the client browser (the user).  In the case of Sanibel Logic, and with many corporations, this is significant because the user may be in one time zone, while the ASP.NET web server hosting provider may be in another time zone.  

 ClientTime2_2 Click image to enlarge...

CLICK HERE to review the online ClientTime class documentation.

CLICK HERE to download the ClientTime VS.NET 2008 source project.

To activate ClientTime, simply drop the ClientTime custom control onto the ASP.NET master page or content page, illustrated as follows:

   1:  </head>
   2:  <body>
   3:      <form id="form1" runat="server">
   4:      
   5:      <asp:ScriptManager id="ScriptManager1" runat="server" AsyncPostBackTimeout="999">
   6:          <Scripts>
   7:              <asp:ScriptReference Path="~/Scripts/Ajax/ModalPopup.js" />
   8:              <asp:ScriptReference Path="~/Scripts/Ajax/ModalPopupConfirmation.js" />
   9:          </Scripts>
  10:      </asp:ScriptManager>
  11:      
  12:      <slcms:ClientTime ID="cltClientTime" runat="server" />
  13:      
  14:      <asp:HiddenField id="hflCurrentDiv" runat="server" /> 

The presence of the ClientTime custom control will cause the time zone related JavaScript to be injected.  To examine any of the ClientTime public properties or invoke any of the ClientTime methods simply reference the ClientTime custom control (or use FindControl if necessary).

ListView Header Sort Direction Indicators

The ASP.NET version 3.5 ListView provides developers with a much needed breath of fresh air with respect to simplifying HTML complexity when a data bound grid control is needed.  The ListView enables developers to have full control over generated HTML, yet have simplified data binding, custom paging and column sorting features.  While column sorting is provided with ListView, a clear indication as to which column has been most recently sorted is not provided.  There are many techniques on the Internet for providing DataGrid and GridView column sort indicators.  The purpose of this posting is to provide a custom control for providing a ListView column sort indicator.

 SortIndicator2_3

This ListView column sort indicator consists of two custom controls; a ListViewSort custom control, which inherits from ListView and a ListViewSortColumnHeader composite custom control.  The ListViewSortColumnHeader control is used when defining each sortable header within the ListView LayoutTemplate.  The ListViewSort custom control is used in place of the ListView ASP.NET control and exposes the following extension public properties:

  • ImageUrlAscending - The image file which is used to represent an ascending sort direction in the active sorted header.  If omitted, an embedded web resource is used as the default.
  • ImageUrlDescending - The image file which is used to represent an descending sort direction in the active sorted header.  If omitted, an embedded web resource is used as the default.
  • SortExpressionDefault - The name of the data element which is the default sort expression.
  • SortDirectionDefault - The initial sort direction when a header is sorted.

Other than the above extension public properties, the ListViewSort is identical to the ListView, illustrated as follows:

           
   1:  <myControls:ListViewSort ID="listViewSort" 
   2:      DataSourceID="ObjMenu" 
   3:      DataKeyNames="Name"
   4:      SortExpressionDefault="Name"
   5:      SortDirectionDefault="Ascending"
   6:      runat="server">
   7:      <LayoutTemplate>
   8:          <table runat="server" 
   9:              class="listViewGrid"
  10:              cellspacing="0"
  11:              border="0">
  12:              <tr>
  13:                  <th>
  14:                      <myControls:ListViewSortColumnHeader runat="server"
  15:                          Key="Name"
  16:                          Text="Food Name" />
  17:                  </th>
  18:                  <th>
  19:                      <myControls:ListViewSortColumnHeader runat="server"
  20:                          Key="Price"
  21:                          Text="Price" />
  22:                  </th>
  23:                  <th>
  24:                      <myControls:ListViewSortColumnHeader runat="server"    
  25:                          Key="Description"
  26:                          Text="Description" />
  27:                  </th>
  28:                  <th>
  29:                      <myControls:ListViewSortColumnHeader runat="server"
  30:                          Key="Calories"
  31:                          Text="Calories" />
  32:                  </th>
  33:              </tr>
  34:              
  35:              <tr runat="server" id="itemPlaceholder" />
  36:          
  37:          </table>
  38:          <asp:DataPager ID="dataPager" runat="server">
  39:              <Fields>
  40:                  <asp:NumericPagerField ButtonCount="10"
  41:                      NextPageText="..."
  42:                      PreviousPageText="..." />     
  43:              </Fields>
  44:          </asp:DataPager>
  45:      </LayoutTemplate>
  46:      <ItemTemplate>
  47:          <tr class="<%# ((ListViewDataItem)Container).DisplayIndex % 2 == 0 ? "itemRow" : "altItemRow" %>">
  48:              <td align="left" style="width: 200px;">
  49:                  <asp:Label runat="server" 
  50:                      Text='<%# Eval("Name") %>' />
  51:              </td>
  52:              <td align="right" style="width: 100px;">   
  53:                  <asp:Label runat="server" 
  54:                      Text='<%# Eval("Price") %>' />
  55:              </td>
  56:              <td align="left" style="width: 400px;">
  57:                  <asp:Label runat="server" 
  58:                      Text='<%# Eval("Description") %>' />
  59:              </td>
  60:              <td align="right" style="width: 100px;">
  61:                  <asp:Label runat="server" 
  62:                      Text='<%# Eval("Calories") %>' />
  63:              </td>
  64:          </tr>
  65:      </ItemTemplate>
  66:  </myControls:ListViewSort>    
  67:                                      
  68:  <asp:ObjectDataSource ID="ObjMenu" runat="server" 
  69:      EnablePaging="true"
  70:      SelectMethod="GetRows" 
  71:      SelectCountMethod="GetRowCount" 
  72:      TypeName="SanibelLogic.MenuDataSource.DataIO" 
  73:      DataObjectTypeName="SanibelLogic.MenuDataSource.Elements"
  74:      MaximumRowsParameterName="MaximumRows" 
  75:      StartRowIndexParameterName="StartRowIndex"                
  76:      SortParameterName="SortExpression">
  77:      <SelectParameters>
  78:          <asp:Parameter Name="SortExpression" 
  79:              Type="String" />
  80:          <asp:Parameter Name="MaximumRows" 
  81:              Type="Int32" />
  82:          <asp:Parameter Name="StartRowIndex" 
  83:              Type="Int32" />
  84:      </SelectParameters>
  85:  </asp:ObjectDataSource>

The ListViewSortColumnHeader composite control is used in place of a HyperLink ASP.NET control, normally used to activate column sorting.  ListViewSortColumnHeader exposes the Key  and Text  properties.  The Key  property associates the header with a databound expression, while the Text  property provides for the actual text being displayed in the header.  The ListViewSortColumnHeader control essentially generates the asp:HyperLink control and an asp:PlaceHolder control for an anticipated asp:Image control whenever the header participates in a sorting operation.

The ListViewSort custom control overrides a single event from the inherited ListView control; OnDataBound, illustrated as follows:

   1:  protected override void OnDataBound(EventArgs e)
   2:  {
   3:      if (base.SortExpression.Length == 0)
   4:      {
   5:          if (SortExpressionDefault.Length > 0)
   6:          {
   7:              base.Sort(SortExpressionDefault, SortDirectionDefault);
   8:          }
   9:      }
  10:   
  11:      List<Control> controls = Helpers.GetControlsByType(this, typeof(ListViewSortColumnHeader));
  12:      foreach (Control control in controls)
  13:      {
  14:          ListViewSortColumnHeader header = (ListViewSortColumnHeader)control;
  15:          if (header.HasSortDirectionIndicator() == true)
  16:          {
  17:              header.ResetSortDirectionIndicator();
  18:          }
  19:      }
  20:   
  21:      foreach (Control control in controls)
  22:      {
  23:          ListViewSortColumnHeader header = (ListViewSortColumnHeader)control;
  24:          if (header.Key == base.SortExpression)
  25:          {
  26:              header.SetSortDirectionIndicator(base.SortExpression, base.SortDirection);
  27:              break;
  28:          }
  29:      }
  30:   
  31:      base.OnDataBound(e);
  32:  }


During ListViewSort OnDataBound event processing, the existing ListViewSort headers are examined and any existing sort direction indicator asp:Image controls are removed and then the appropriate sort direction indicator asp:Image control is injected into the new header being sorted.  With the exception of maintaining the four ListViewSort extension public properties within ViewState, that is essentially all that ListViewSort does.  This level of simplicity ensures that sort direction indicator logic does not need to work its way into your application for each and every web page which uses a ListView.  Sample ListViewSort output is illustrated below.  In this illustration (and related project demo file) any of the headers can be clicked and the table data will be sorted in either ascending or descending order.

The project demo file for the above sample HTML and code above also demonstrates usage of an ASP.NET ObjectDataSource control, enabled for custom paging, to ensure that only the currently displayed ListViewSort data is maintained within ViewState at any point in time.

Click HERE to download VS.NET 2008 project demo file.

A New Generation of URL Rewriters ?

I have always had problems finding a suitable ASP.NET URL Rewriter that fully meets my needs, so about one year ago, after much frustration with attempting to follow third party open-source code and related poor documentation, I decided to write my own. I have since repackaged this URL Rewriter/ Redirector into the name of nUrlRewriter Version 2.  nUrlRewriter has been posted on popular download sites, such as codeplex.com and code.msdn.microsoft.com   The nUrlRewriter Version 2 open source VS.NET 2008 project can also be downloaded from our site by clicking HERE.

nUrlRewriter is a ASP.NET Http Module written in managed C# code. nUrlRewriter examines incoming Http requests and applies user defined criteria which may result in a Http request being redirected or rewritten. Web pages within existing web sites are often archived or retired, however many Internet based hyperlinks may exist for such web pages. nUrlRewriter solves this problem by providing a facility which can easily redirect or rewrite such Http requests to other web site web pages or web applications. For example, a discontinued product web page may be redirected to a general product category web page. nUrlRewriter differentiates itself from other redirectors/rewriters in that nUrlRewriter also supports the IIS7 Integrated Pipeline, enabling nUrlRewriter to redirect/rewrite any incoming web application URL supported by the IIS7 web server, such as but not limited to native HTML applications (htm, html), classic ASP applications (asp), PHP applications (php) as well as ASP.NET (aspx) applications.

Incoming Http requests which are redirected are returned to the originating browser with a status code of either 301 (permanent) or 302 (temporary) to indicate that the requested web page has been moved to a new target URL provided to the browser. the browser will then issue a new Http request for the new URL. Http status code 301 indicates that the URL has been permanently moved and the browser should use the new URL in any new Http requests. Http status code 302 indicates that the URL has been temporarily moved and the browser should use the new URL only for the outstanding Http request.

Incoming Http requests which are rewritten are rewritten to a different URL location within IIS. Since the originating browser is not informed of the URL rewrite, the browser URL address bar will continue to display the originating URL before the URL rewrite.

nUrlRewriter works equally as well with IIS5 and IIS6.

Background

Clearly, with an all new internal architecture and with new enriched Remote Administration and Feature Delegation enhancements, IIS7 opens up a new generation of web hosting and demands a new generation of support infrastructure tools as well; such as Url Rewriters/ Redirectors.

nUrlRewriter not only works well in an IIS5 or IIS6 environment, but nUrlRewriter takes advantage of the new IIS7 Integrated ASP.NET Pipeline to simplify communications between native HTML applications (.htm, .html), classic ASP (.asp), PHP applications (.php) and ASP.NET (.aspx).

nUrlRewriter can be used for the following:

  1. To redirect/rewrite in case of retired or archived web pages.
  2. To rewrite from a friendly URL format to an internal URL format.
  3. To redirect to secondary folder locations; for example language specific web site content may reside in separate folders, or a single IP address may be hosting multiple web sites, with the domain specific content residing in sub-folders.
  4. To provide for URL specific robots.txt files.  For example if a single IP address is supporting multiple web sites, then web site specific robots.txt files can be returned when requested.

 

Redirecting Incoming Http Requests

WebRedirection_6

 

Rewriting Incoming Http Requests

WebRewriting[2]

 

Using with IIS Version 5 or 6

nUrlRewriter executes in the form of a Http Module, so nUrlRewriter must be defined in the web.config <system.web> <httpModules> configuration section, as illustrated below:

   1:    <system.web>
   2:      <httpModules>
   3:        <add name="nUrlRewriter"
   4:             type="nUrlRewriter.HttpModule, 
   5:                    nUrlRewriter,
   6:                    Version=2.0.0.0,
   7:                    Culture=neutral,
   8:                    PublicKeyToken=741b921e11e02781"/>      
   9:      </httpModules>
  10:    </system.web>
 

To configure specific nUrlRewriter options, the nUrlRewriter web.config configuration section must now be declared, as illustrated below:

   1:    <configSections>
   2:      <section name="nUrlRewriter" 
   3:               type="nUrlRewriter.Configuration2.Configuration, 
   4:                      nUrlRewriter,
   5:                      Version=2.0.0.0,
   6:                      Culture=neutral,
   7:                      PublicKeyToken=741b921e11e02781"/>
   8:    </configSections>

Once the nUrlRewriter Http Module is defined and the nUrlRewriter configuration section is declared, the nUrlRewriter specific configuration section must be defined within the web.config.

I am currently supporting two web sites; my corporate web site -  www.sanibellogic.com and my personal web site -  www.plippard.com.  The entry point for both sites is at the root level (wwwRoot), with a common IP address.  Any future additional web sites being hosted will also share the same IP address. The root level of my web site redirects based on domain name, and then more specific redirect/ rewrite logic is applied at the sub-folder (or actual web site sub-folder) level.  Essentially, at the wwwRoot level, sanibellogic.com domains are redirected to the “/SL” sub-folder, and plippard.com domains are redirected to the “/PGL” sub-folder. Because these sites are currently being hosted on IIS6, IIS7 specific features are not currently used. IIS7 specific features will be discussed later in this article.

The following exhibit shows the root level nUrlRewriter configuration section for achieving the above discussed domain redirection:

   1:  <?xml version="1.0" encoding="utf-8" ?>
   2:  <nUrlRewriter xmlns="http://schemas.sanibellogic.com/nUrlRewriter/config/2/0/0/0"
   3:                enabled="true"
   4:                trace="false">
   5:    <urls>
   6:      <clear/>
   7:   
   8:      <add name="RuleSanibelLogic"
   9:           action="redirect"
  10:           ignoreCase="true" 
  11:           redirectType="temporary"
  12:           transformType="RegExReplace"
  13:           fromScope="absolute"
  14:           from="^http(?&lt;SSL&gt;[s]?)://(www.)?sanibellogic.com/(?&lt;WebPage&gt;(.*))$"
  15:           to="http${SSL}://www.sanibellogic.com/sl/${WebPage}" />
  16:   
  17:      <add name="RulePLippard"
  18:           action="redirect"
  19:           ignoreCase="true"
  20:           redirectType="temporary"
  21:           transformType="RegExReplace"
  22:           fromScope="absolute"
  23:           from="^http(?&lt;SSL&gt;[s]?)://(www.)?plippard.com/(?&lt;WebPage&gt;(.*))$"
  24:           to="http${SSL}://www.plippard.com/pgl/${WebPage}" />
  25:   
  26:    </urls>
  27:  </nUrlRewriter>

The above configuration section exhibit primarily examines the incoming domain name, transforms the absence of a sub-domain to "www." and then redirects the incoming request to a defined ASP.NET application sub-folder (either /SL or /PGL) based on whether the domain is "sanibellogic.com" or "plippard.com". All sub-folder or query string content following the domain name is also appended to the redirected request.

Once the incoming request is intercepted and redirected to the proper ASP.NET application sub-folder, nUrlRewriter (operating in the context of the /SL or /PGL sub-folder) will again have an opportunity to intercept and redirect or rewrite the new incoming request, .  The exhibit below shows the ASP.NET application folder level  configuration section used by nUrlRewriter when operating in the context of the /SL sub-folder:

   1:  <nUrlRewriter xmlns="http://schemas.sanibellogic.com/nUrlRewriter/config/2/0/0/0"
   2:                enabled="true"
   3:                trace="false">
   4:    
   5:    <urls>
   6:      <clear/>
   7:   
   8:      <!-- Rewrite one time DownloadMe.aspx root level DownloadMe page to new location,
   9:            Note: rewriteType="transferrequest" requires IIS7 Integrated Pipeline mode -->
  10:      <add name="RuleDownloadMe"
  11:           action="rewrite"
  12:           rewriteType="rewritePath"
  13:           ignoreCase="true"
  14:           transformType="RegExReplace"
  15:           from="~/DownloadMe.aspx(?&lt;QStrings&gt;(.*))$"
  16:           to="~/Common/S/DownloadMe.aspx${QStrings}" />
  17:   
  18:      <!-- Rewrite ECartDownload.aspx web page to new location,
  19:            Note: rewriteType="transferrequest" requires IIS7 Integrated Pipeline mode -->
  20:      <add name="RuleECartDownload"
  21:           action="rewrite"
  22:           rewriteType="rewritePath"
  23:           ignoreCase="true"
  24:           transformType="RegExReplace"
  25:           from="~/Common/ECartDownload.aspx(?&lt;QStrings&gt;(.*))$"
  26:           to="~/Common/S/ECartDownload.aspx${QStrings}" />
  27:   
  28:      <!-- Rewrite PaypalIPN web page to new location,
  29:            Note: rewriteType="transferrequest" requires IIS7 Integrated Pipeline mode -->
  30:      <add name="RulePaypalIPN"
  31:           action="rewrite"
  32:           rewriteType="rewritePath"
  33:           ignoreCase="true"
  34:           transformType="RegExReplace"
  35:           from="~/Common/PaypalIPN.aspx(?&lt;QStrings&gt;(.*))$"
  36:           to="~/Common/S/PaypalIPN.aspx${QStrings}" />
  37:   
  38:      <!-- Redirect one time Products.aspx root level Products page to new location -->
  39:      <add name="RuleProducts"
  40:           action="redirect"
  41:           ignoreCase="true"
  42:           redirectType="permanent"
  43:           transformType="RegExReplace"
  44:           from="~/Products.aspx(?&lt;QStrings&gt;(.*))$"
  45:           to="~/Common/Products.aspx${QStrings}" />
  46:   
  47:      <!-- Redirect discontinued Products.aspx DotNetNuke SSLRedirect queries -->
  48:      <add name="RuleDotNetNuke00200"
  49:           action="redirect"
  50:           ignoreCase="true"
  51:           redirectType="permanent"
  52:           transformType="RegExReplace"
  53:           from="~/Common/Products.aspx\?Cat=DotNetNuke&amp;PLong=00200$"
  54:           to="~/Common/Products.aspx?Cat=ASP.NET&amp;PLong=00401" />
  55:   
  56:      <!-- Redirect discontinued Products.aspx DotNetNuke SSLRedirect SDK queries -->
  57:      <add name="RuleDotNetNuke00201"
  58:           action="redirect"
  59:           ignoreCase="true"
  60:           redirectType="permanent"
  61:           transformType="RegExReplace"
  62:           from="~/Common/Products.aspx\?Cat=DotNetNuke&amp;PLong=00201$"
  63:           to="~/Common/Products.aspx?Cat=ASP.NET&amp;PLong=00402" />
  64:   
  65:      <!-- Redirect discontinued Products.aspx DotNetNuke SmartNews queries -->
  66:      <add name="RuleDotNetNuke00202"
  67:           action="redirect"
  68:           ignoreCase="true"
  69:           redirectType="permanent"
  70:           transformType="RegExReplace"
  71:           from="~/Common/Products.aspx\?Cat=DotNetNuke&amp;PLong=00202$"
  72:           to="~/Common/Products.aspx?Cat=ASP.NET" />
  73:   
  74:      <!-- Redirect discontinued Products.aspx DotNetNuke SmartNews SDK queries -->
  75:      <add name="RuleDotNetNuke00203"
  76:           action="redirect"
  77:           ignoreCase="true"
  78:           redirectType="permanent"
  79:           transformType="RegExReplace"
  80:           from="~/Common/Products.aspx\?Cat=DotNetNuke&amp;PLong=00203$"
  81:           to="~/Common/Products.aspx?Cat=ASP.NET" />
  82:   
  83:      <!-- Redirect discontinued Products.aspx DotNetNuke HttpCompressionAgent queries -->
  84:      <add name="RuleDotNetNuke00204"
  85:           action="redirect"
  86:           ignoreCase="true"
  87:           redirectType="permanent"
  88:           transformType="RegExReplace"
  89:           from="~/Common/Products.aspx\?Cat=DotNetNuke&amp;PLong=00204$"
  90:           to="~/Common/Products.aspx?Cat=ASP.NET&amp;PLong=00400" />
  91:   
  92:      <!-- Redirect discontinued Products.aspx DotNetNuke product category -->
  93:      <add name="RuleDotNetNuke"
  94:           action="redirect"
  95:           ignoreCase="true"
  96:           redirectType="permanent"
  97:           transformType="RegExReplace"
  98:           from="~/Common/Products.aspx\?Cat=DotNetNuke$"
  99:           to="~/Common/Products.aspx?Cat=ASP.NET" />
 100:      
 101:    </urls> 
 102:   
 103:  </nUrlRewriter>

As can be seen from the above nUrlRewriter configuration sections, nUrlRewriter can be easily extended without code source changes, simply by  defining the actions required in the configuration section.

Using with IIS Version 7 (Windows Server 2008 and Vista)

Once released, I fully expect to take advantage of the much publicized and anticipated Windows Server 2008 IIS7 features. When one plans on utilizing the more advanced IIS7 features, and one’s web application is defined to IIS7 as executing in “Integrated ASP.NET Pipeline” mode then nUrlRewriter is defined in a slightly different manner within the web.config. The nUrlRewriter Http Module is now defined within the new  <system.webserver> configuration section, illustrated below:

   1:    <system.webServer>
   2:      <modules>
   3:        <add name="nUrlRewriter"
   4:             type="nUrlRewriter.HttpModule, 
   5:                    nUrlRewriter,
   6:                    Version=2.0.0.0,
   7:                    Culture=neutral,
   8:                    PublicKeyToken=741b921e11e02781"/>
   9:      </modules>    
  10:    </system.webServer>

The nUrlRewriter configuration section continues to be declared and defined as with IIS5/6, illustrated as follows:

   1:    <configSections>
   2:      <section name="nUrlRewriter"
   3:               type="nUrlRewriter.Configuration2.Configuration, 
   4:                      nUrlRewriter,
   5:                      Version=2.0.0.0,
   6:                      Culture=neutral,
   7:                      PublicKeyToken=741b921e11e02781"/>
   8:    </configSections>

One of the nUrlRewriter configuration options available with IIS7 is the ability to rewrite/ redirect between any web application supported by the IIS7 web server, such as but not limited to native HTML applications (htm, html), classic ASP applications (asp), PHP applications (php) as well as ASP.NET (aspx) applications. To achieve this objection (for example), one would configure the nUrlRewriter configuration section as follows:

   1:  <nUrlRewriter xmlns="http://schemas.sanibellogic.com/nUrlRewriter/config/2/0/0/0"
   2:                              enabled="true"
   3:                              trace="false">
   4:   
   5:      <topLevelExtensions>
   6:          <clear/>
   7:          <add extension="asp" />
   8:          <add extension="aspx" />
   9:          <add extension="htm" />
  10:          <add extension="html" />
  11:          <add extension="php" />
  12:      </topLevelExtensions>
  13:   
  14:      <urls>
  15:          <clear/>
  16:   
  17:          <!-- Redirect WordPress blog URL, which was a sub-folder within an ASP.NET App
  18:                      to new ASP.NET BlogEngine.Net sub-folder -->
  19:          <add name="RuleBlog"
  20:                   action="redirect"
  21:                   from="~/support/wpblog/(.+)"
  22:                   to="~/support/beblog/" />
  23:      </urls>
  24:   
  25:  </nUrlRewriter>

Please note that the topLevelExtensions tag defines the candidate web page extensions, required for PHP application visibility in this example.

With IIS7, another common use of nUrlRewriter will be support for multiple robots.txt files.   The robots.txt file is ordinarily required to be at the root level of a web site. The following nUrlRewriter configuration section illustrates rewriting a web request for a root level robots.txt file to a sub-folder resident robots.txt, making its sub-folder location transparent to the invoking search engine. The to attribute MUST be transformed into a relative URL location, which starts with "~/", because both the System.Web.HttpServerUtility.TransferRequest and System.Web.HttpContext.RewritePath methods require a relative URL path. Please note that the "txt" extension must also be included within the topLevelExtensions collection.

   1:    <nUrlRewriter xmlns="http://schemas.sanibellogic.com/nUrlRewriter/config/2/0/0/0"
   2:                  enabled="true"
   3:                  trace="false">
   4:   
   5:          <topLevelExtensions>
   6:              <clear/>
   7:                  <add extension="asp" />
   8:                  <add extension="aspx" />
   9:                  <add extension="htm" />
  10:                  <add extension="html" />
  11:                  <add extension="php" />
  12:                  <add extension="txt" />
  13:   
  14:          </topLevelExtensions>
  15:          
  16:          <urls>
  17:              <clear/>
  18:   
  19:              <!-- Based on incoming domain of SanibelLogic.com, rewrite to a -->
  20:              <!-- sub-folder location for the robots.txt file -->
  21:              <add name="RuleSanibelLogicRobots"
  22:                      action="rewrite"
  23:                      rewriteType="transferRequest"
  24:                      fromScope="absolute"
  25:                      from="^http(?&lt;SSL&gt;[s]?)://(www.)?sanibellogic.com/(?&lt;robotsFile&gt;(robots.txt))$"
  26:                      to="~/SL/$(robotsFile)" />
  27:   
  28:              <!-- Based on incoming domain of PLippard.com, rewrite to a -->
  29:              <!-- sub-folder location for the robots.txt file -->
  30:              <add name="RulePLippardRobots"
  31:                      action="rewrite"
  32:                      rewriteType="transferRequest"
  33:                      fromScope="absolute"
  34:                      from="^http(?&lt;SSL&gt;[s]?)://(www.)?plippard.com/(?&lt;robotsFile&gt;(robots.txt))$"
  35:                      to="~/PGL/$(robotsFile)" />
  36:   
  37:          </urls>
  38:    </nUrlRewriter>

A URL rewriting/ redirecting web component is essential for effective management of multiple as well as single web sites. nUrlRewriter utilizes new and advanced IIS7 Integrated ASP.NET Pipeline features to ensure that all web applications, such as but not limited to native HTML applications (htm, html), classic ASP applications (asp), PHP applications (php), and ASP.NET applications (aspx) are integrated in an effective manner.    nUrlRewriter also utilizes regular expressions and a flexible configuration design to ensure ease of expansion without source code changes.  nUrlRewriter documentation in .chm help file form is available with the VS.NET 2008 source code project download.

Click HERE to download the nUrlRewriter open source VS.NET 2008 project.