Introduction
In this article I will demonstrate how a web application can benefit from the use of Page Modules using, for the demonstration, the Page Flow Store Quick Start and the Page Flow Application Block shipped with the Web Client Software Factory.
Creating the Page Module
The first step is creating a Page Module that will replace the HTTP Module used by the Page Flow Application Block.
Since the Page Module will only be called for pages (.aspx), there is no longer need to register extensions for pages and check in every HTTP Request if the request is for a page making the PageFlowPageModule simpler that the PageFlowHttpModule.
namespace PauloMorgado.Practices.PageFlow.Extensions
{
public class PageFlowPageModule : PauloMorgado.Web.UI.IPageModule
{
#region IPageModule Members
public void Init(PauloMorgado.Web.UI.PageHandlerFactoryWithModules context)
{
context.PageCreated += new System.EventHandler<PauloMorgado.Web.UI.PageCreatedEventArgs>(OnPageCreated);
}
#endregion
void OnPageCreated(object sender, PauloMorgado.Web.UI.PageCreatedEventArgs e)
{
int rootSplitter = e.VirtualPath.IndexOf('/', 1);
string path = '~' + e.VirtualPath.Substring(rootSplitter);
Microsoft.Practices.PageFlow.ProcessResult result = Microsoft.Practices.PageFlow.PageFlowDirectory.Provider.ProcessRequest(path);
if (result.ShouldRedirect)
{
System.Web.HttpContext.Current.Server.Transfer(result.RedirectUrl, false);
}
}
}
}
Registering the Page Module
Now that I have a Page Module, I just need to replace the HTTP Module with it.
The first step is registering the PageHandlerFactoryWithPageModules as the handler factory for *.aspx requests:
<?xml version="1.0"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<configSections>
<sectionGroup name="PauloMorgado.web">
<section name="pageModules"
type="PauloMorgado.Web.Configuration.PageModulesSection, PauloMorgado.Web.UI.PageHandlerFactoryWithModules"/>
</sectionGroup>
</configSections>
<system.web>
<!--
...
-->
<httpHandlers>
<remove verb="*" path="*.aspx"/>
<add verb="*" path="*.aspx" validate="false"
type="PauloMorgado.Web.UI.PageHandlerFactoryWithModules, PauloMorgado.Web.UI.PageHandlerFactoryWithModules"/>
</httpHandlers>
<!--
...
-->
</system.web>
<PauloMorgado.web>
<pageModules>
</pageModules>
</PauloMorgado.web>
</configuration>
The second step is registering the PageFlowPageModule as a Page Module:
<?xml version="1.0"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<!--
...
-->
<PauloMorgado.web>
<pageModules>
<add name="PageFlowModule"
type="PauloMorgado.Practices.PageFlow.Extensions.PageFlowPageModule, PauloMorgado.Practices.PageFlow.Extensions"/>
</pageModules>
</PauloMorgado.web>
</configuration>
And, finally, I need the remove the PageFlowHttpModule from HTTP Modules list:
<?xml version="1.0"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<!--
...
-->
<system.web>
<!--
...
-->
<httpModules>
<!--<add name="PageFlowModule"
type="Microsoft.Practices.PageFlow.PageFlowHttpModule, Microsoft.Practices.PageFlow"/>-->
</httpModules>
<!--
...
-->
</system.web>
<!--
...
-->
</configuration>
Changing the Navigation Service
One of the benefits of using Page Modules is that there is no longer the need to issue client-side redirects to navigate to another page. For that reason, the only change need in the navigation service is replacing the call to the HttpResponse.Redirect method for a call to the HttpServerUtility.Transfer method.
public void RedirectTo(Page page)
{
Guard.ArgumentNotNull(page, "page");
HttpContext.Current.Server.Transfer(page.Url, false);
}
Testing the Page Flow Page Module
Now that I have it all set up, all I need is run it.
For the purpose of the demonstration I'll compare the results between the usage of an HTTP Module and a Page Module.
The Use Case
The test the application I'll do a simple shopping session that consists of the following steps:
- Login
- Start the page flow
- Browse the catalog
- Add an item to the shopping cart
- Checkout the order
- Enter payment data
- End the shopping session
Analyzing the steps
|
Screen |
With HTTP Module |
With Page Module |
Comments |
| |
|
|
The first request just gets the first page. |
 |
|
|
The user enters the credentials and presses the Log In button. |
| |
|
|
The second page is the login page.
As usual with FormsAuthentication, the request is redirected via a client side redirection.
At this point there are still no changes in the behavior of the application. |
 |
|
|
The user presses the Start Store Page Flow button. |
| |
 |
 |
This is were we start noticing the changes.
As you can notice, with the HTTP Module, the navigation to the next page is issued via a client side redirection.
On the other hand, with the Page Module, the navigation is done server side saving one request. |
 |
|
|
The user presses the Browse Catalog link button. |
| |
 |
 |
With the HTTP Module, the navigation to the next page is issued via a client side redirection.
With the Page Module, the navigation is done server side saving one request. |
 |
|
|
The user selects a product by pressing the Add to cart link button. |
| |
 |
 |
With the HTTP Module, the navigation to the next page is issued via a client side redirection.
With the Page Module, the navigation is done server side saving one request |
 |
|
|
The user presses the Checkout Order link button to complete the shopping session. |
| |
 |
 |
With the HTTP Module, the navigation to the next page is issued via a client side redirection.
With the Page Module, the navigation is done server side saving one request |
 |
|
|
The user enters the payment data and presses the Submit Order button. |
| |
 |
 |
With the HTTP Module, the navigation to the next page is issued via a client side redirection.
With the Page Module, the navigation is done server side saving one request |
 |
|
|
The shopping session is completed. |
The complete navigation charts are here:
|
With HTTP Module |
With Page Module |
 |
 |
Conclusion
With this simple example is already possible to show the benefits of using Page Modules. The reasons for this I already explained here.
In a real life scenario the benefits tend to increase because more complex page flows can be defined, with navigations being triggered by application logic instead of just user direct action without the concern for the weight of client side redirections.
Images captured with SnagIt. Page traffic captured with IEWatch.
Filed under: .NET, Architecture, ASP.NET, Community, SoftDev, C#, Microsoft, MSDN, MVP, Web, WCSF, PnP, SoftwareFactories, PageFlow, PageModules