Blogs

Intelligent Design

Typed Navigation

One of the features we've worked into our new home-grown architecture is typed navigation.  Without typed navigation, urls are strewn throughout the code, and any changes to navigation or querystrings involve updates to many pages.  Not only that, providing a page the data it needs to properly initialize can be difficult to manage and very easy to misunderstand by a developer who is working in a page they're not familiar with.  These issues cause navigation edits to be error-prone and reduce maintainability and extensibility.

The Need  

Consider the following common scenario - You've got a page (let's say EmployeeDetail.aspx) that requires an EmployeeID be passed to it.  There are many different ways to get the ID to the page:

  • QueryString - EmployeeDetail.aspx?empID=100
  • Session - Session["EmployeeID"] = 100
  • Database retrieval
  • etc...

Each method involves different code to set and retrieve the value.  In addition, almost every app uses multiple methods in different places and in different scenarios.  This results in too many decisions being made by too many different developers, which results in maintenance nightmares.  Strict processes can mitigate some of the maintenance pain, if all of your developers ALWAYS use the exact same mechanism, but what about extensibility?  What if the page name needs to change at some point?  What if you decide to change the way you handle data transfer between pages?  Or, more commonly, what if a page simply changes the data it needs or accepts?

Cascading Style Sheets (CSS) is a good example of an architecture with big benefits in UI design - you can make a style change in one place, and that change gets applied in all pages where that style is used.  The same measuring stick can be applied to all architectures - can you make a configuration change in a few places (preferably one), and have it applied in all areas of usage?  I think most apps would fail this measure in the area of navigation.  If a page name changes, most application architectures would require manual changes in many pages - links, code behind redirects, data tables, etc.  Even more architectures would fail the test if a change is made to how data is transferred.  If a QueryString value changes from empID, to eID, how many code changes would need to be made?  What if a page now requires an orgID?  Or how about if you move from QueryString to Session, or vice versa?  This is where good architectures shine in the long run.  Yes you can continue to change the font manually in all your pages when your app is small, but heavy usage of CSS is now widely accepted as best-practice simply because style maintenance and extensibility become absolutely crazy as the number of pages in your site gets large.  Why should navigation be any different?  It gets just as crazy as your app gets large, and can benefit just as much from a consolidated architecture.

The Solution

Our solution is to use typed navigation.  There are several potential architectures available, one of which is PageMethods.  There's a great list of the benefits of typed navigation on that page, so I'll try not to rehash all of them here.  We took a good look at this solution before developing our own architecture, but decided we wanted much more control over our navigation.  Also, the PageMethods solution is locked into generating urls with QueryStrings, and it involves pages calling specific methods in other pages, which our new architecture steers clear of due to MVC principles. 

Our architecture includes the following:

  • Typed Location objects - every navigation destination (View) has its own Location class
  • Each Location class defines a constant "ViewName" which maps to a url defined in a database, so no urls or page names are ever written in code 
  • Each Location class can have multiple constructors - the constructors provide all the contracts to create the View and allow pages to fulfill multiple roles (list/detail based on what data is sent to them)
  • Usage in links - a new Location object is created in code-behind and used to set the Location property on one of our HyperLink controls.  If set, the HyperLink control has the Location generate its URL when the control is rendered. 
  • Usage in server-side redirects - a controller simply creates a new Location object and calls a public Navigate method on its View
  • Hydrating Location objects - our base Page class takes care of rehydrating the location object and transferring its data to the View

Here are the only two options a developer will see regarding Navigation in our app:

For a HyperLink:

lnkEmployeeDetail.Location = new EmployeeDetailLocation(employeeID);

For a server-side redirect:

_myView.Navigate(new EmployeeDetailLocation(employeeID));

Since all this is handled by the architecture, changes can be made in just a few places and totally change the Navigation mechanism.  We can switch from QueryStrings to Session variables, or rewrite URLs, or change how we rewrite URLs as often as we want.  No code that actually uses the Navigation would ever need to change, and page names can change without missing a beat.  All the code written to create strongly-typed Location objects would continue to navigate as usual.  If a page's initialization requirements changed, then code would break at compile time instead of runtime, with a very clear and self-describing explanation of exactly how the new Location object needs to be constructed.  That's a lot better than having some forgotten link deep in your app with an obsolete parameter definition getting discovered by a customer after you've published your app to production.

Typed Navigation is one more step we're taking to make our code easy to work with and understand, regardless of how long it's been since anyone's touched it, how many developers have had their hands in it, or how large it grows.

 

Published Tuesday, January 09, 2007 11:12 AM by thardy

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

No Comments

Leave a Comment

(required) 
(optional)
(required) 
Submit