Publish Date: 6/21/2007
Problem:
You and Joe are working on a sizable web application. Nasty-Coder Joe, who is on another team, creates a new page
that requires 2 session variables and a query string parameter in order for his page to work properly.
You now need to pass data to this page to finish your last feature before you leave for vacation in one
hour. Without reading Nasty-Coder Joe's code to try and figure out what the necessary session variables and QueryString
paramenters are, how do you use his page?
Introduction:
Controlling page flow on the web has a number of distinct problems. Since the web is literally a
"web" often the entry points to any one page are numerous. Many developers have come up with
solutions to addressing the problem of page-flow in a web application, but the solutions sometimes end up
becoming a thick mire of XML structures that try to be predictive in page-flow rather than facilitate the
choose-your-own-adventures style of navigation often found in a web app.
Web Navigator is a technique, or pattern or approach that I came up with when I was faced with the
same problem as stated at the beginning of this show. I was working alongside a developer who was creating
pages that I needed to use, but I had no idea how to pass the correct information to the page.
What I came up with I call "WebNavigator".
Yes, I know I was wearing my terribly-original-idea-hat that day...
Web Navigatior is:
- A way for you to encapsulate the contract that each page has for required data
- If you change the contract, you experience compilation errors
- Abstract the location to pages to support change
- Who really cares if the login page is under a login folder or at the root of the site? You
just want to get your user there!
- A way to organize and create a composable model of your site's navigation
- Once you have tens of pages, how will you know which pages relate to one another?
- A way to allow simple was to weave in and out of secured areas of the site
- Using SSL can be tricky. There are rules about how you must enter and exit secure areas of your
site. Having a object to manage the changes in SSL makes your life easier
What is its Structure?
The syntax is based around a fluent interface. For example if you wanted to navigate
to the homepage of the website, you would use:
WebNavigator.GoTo(WebNavigator.URLFor.Home());
Important points:
- The destination methods (ex: WebNavigator.URLFor.Home())
will always return strings. This is so you can still use the Web Navigator class to build URLs for you without requiring a post
back to build the URL.
- WebNavigator.GoTo() handles the redirection.
You can overload the method to support Server.Transfers and instructions to use SSL
- For example, the following should
give you a very good idea of where the user will end up:
WebNavigator.GoTo(WebNavigator.URLFor.Membership.Login());
- If you have the access to
a page wrapped up in WebNavigator.URLFor.Login() and it's real URL is
http://domain.com/login.aspx, but used to be
http://domain.com/login/default.aspx your website will not experience any broken links. You will
change the mapping to the new location in one place and the rest of the site will reflect this change.
Examples of Encapsulation
When using pages throughout the website, some pages will require simple QueryString values and other pages will need session variables
set and perhaps other requirements. Web Navigator will encapsulate the requirements of a page. When you are a developer consuming the page
all you care about is what the destination method contracts in it's method signature.
For example, the following listing will show you how to pass a user's email address to the login screen.
string userName;
// set userName to something... perhaps from the database
WebNavigator.GoTo(WebNavigator.URLFor.Membership.Login(userName));
Using QueryString Values
The most common use of a destination method is to encapsulate the use of a QueryString parameter. The following example
will show you how to hide the QueryString requirements.
public class Membership
{
public string Login(string userName)
{
return string.Format("~/login/default.aspx?userName={0}",userName);
}
}
Using Session Variables and Other Resources
Sometimes you do not want to pass an item the QueryString, or a page requires a complex-type before you can use it. (Think of a page
requiring an object collection in memory). In these types of cases you could pass the data around in a session variable. The
following will show you how to use session variables.
public class Reports
{
public string SalesReport(OrderCollection orders)
{
System.Web.HttpContext.Current.Session.Add("SalesReport",orders);
return "~/reports/sales.aspx";
}
}
Using this method will set aside anything you need into session and then return the destination URL for you to
use whenever necessary. The fun doesn't have to stop at session variables. You can use the same technique for application
variables, context items, etc.
The point is that what is inside the implementaton does (setup QueryString vales, add Session variables, etc..)
is completely hidden from the developer who is using the page. The method signature of the URLFor method will
establish a contract for any required information for the page.
Contract Changes
If the contract to a page changes, you will encounter compilation errors. If the page in the past
did not require any external data, but then was changed to needing a piece of data, the updated destination method signature
will cause the application to encounter compilation errors where ever the page is used. This will ensure the page is always
getting what it needs.
For instance if your content editor page previously did not require a content ID the method might look
something like this:
WebNavigator.URLFor.ContentEditor();
.
Now you have decided you want to pass in the content ID so the call would look like this:
int contentID;
// get contentID from somewhere
WebNavigator.URLFor.ContentEditor(contentID);
Handling SSL
You can implement it in different ways. I have done it as follows in the past:
WebNavigator.GoTo(WebNavigator.Secure(WebNavigator.URLFor.Login()));
Conculsion
Web Navigator is a pattern that you can use to help manage navigation throughout your websites. The strengths of this technique are:
- Encapsulation of page location
- Public contract of page requirements
- Single place of change for URLs (avoiding broken links)
- Manage SSL "auto-magically"
- Makes code easy to read and maintain