URL Management

Traditionally, using the browser back button or having multiple windows open can cause problems because the Server side Session gets out of synch with the Client. The Navigation framework has no such trouble as it does not use on any Server side cache as all the State, Navigation Data and Crumb Trail is held in the URL during forward, backward, refresh or history Navigation and held in ControlState during PostBacks.

There may be security concerns about certain data appearing in the URL as it is vulnerable to tampering. The ChecksumNavigationShield addresses this as it appends a check digit (checksum) to all URLs. To use this add the configuration shown below. The ‘key’ attribute can be any string but should be kept a secret as it is used in the checksum algorithm. By default the checksum length is eight characters, but this can be overridden by configuring the 'length' attribute.

<configuration>
	<configSections>
		<sectionGroup name="Navigation">
			<section name="StateInfo" type="Navigation.StateInfoSectionHandler, Navigation"/>
			<section name="NavigationShield" type="Navigation.ChecksumNavigationShield, Navigation"/>
		</sectionGroup>
	</configSections>
	<!-- other config elided -->
	<Navigation>
		<StateInfo configSource="StateInfo.config"/>
		<NavigationShield key="checksumkey"/>
	</Navigation>
</configuration>
To implement custom URL obfuscation, create a class inheriting from NavigationShield, override the Encode and Decode methods and refer to this class in the configuration. For example, say there is an id parameter that must never be passed in plain text as it contains sensitive information. The code in below shows a possible Custom NavigationShield (with the Encrypt and Decrypt methods left blank to be filled with an algorithm of choice)

using System.Collections.Specialized;
using System.Security.Cryptography;
using Navigation;

namespace Custom
{
	public class CryptoNavigationShield : NavigationShield
	{
		public override NameValueCollection Encode(NameValueCollection data, bool historyPoint, State state)
		{
			NameValueCollection newColl = new NameValueCollection();
			foreach (string key in data)
			{
				newColl[key] = key != "id" ? data[key] : Encrypt(data[key]);
			}
			return newColl;
		}

		public override NameValueCollection Decode(NameValueCollection data, bool historyPoint, State state)
		{
			NameValueCollection newColl = new NameValueCollection();
			foreach (string key in data)
			{
				try
				{
					newColl[key] = key != "id" ? data[key] : Decrypt(data[key]);
				}
				catch (CryptographicException)
				{
					throw new UrlException();
				}
			}
			return newColl;
		}

		private string Encrypt(string s)
		{
			//Replace with favourite Encryption routine
			return s;
		}

		private string Decrypt(string s)
		{
			//Replace with Decryption routine
			return s;
		}
	}
}
and the code below shows the accompanying configuration.

<configuration>
	<configSections>
		<sectionGroup name="Navigation">
			<section name="StateInfo" type="Navigation.StateInfoSectionHandler, Navigation"/>
			<section name="NavigationShield" type="Custom.CryptoNavigationShield, Custom"/>
		</sectionGroup>
	</configSections>
	<!-- other config elided -->
	<Navigation>
		<StateInfo configSource="StateInfo.config"/>
		<NavigationShield/>
	</Navigation>
</configuration>
Another concern is that URLs can become quite long. There is no prescription on how the State Information is configured nor on how much data is stored in NavigationData and so there is no theoretical URL limit. The SessionCrumbTrailPersister addresses this as it stores Crumb Trails over a specified length (500 is the default) in the Session and appends the Session key for this item onto the URL. To use this add the configuration shown below. To change the default length, configure the 'maxLength' attribute. By default 50 is the maximum number of Crumb Trails stored in Session, but this can be overridden by configuring the 'historySize attribute.

<configuration>
	<configSections>
		<sectionGroup name="Navigation">
			<section name="StateInfo" type="Navigation.StateInfoSectionHandler, Navigation"/>
			<section name="CrumbTrailPersister" type="Navigation.SessionCrumbTrailPersister, Navigation"/>
		</sectionGroup>
	</configSections>
	<!-- other config elided -->
	<Navigation>
		<StateInfo configSource="StateInfo.config"/>
		<CrumbTrailPersister/>
	</Navigation>
</configuration>
To implement custom Crumb Trail storage, create a class inheriting from CrumbTrailPersister, override the Load and Save methods and refer to this class in the configuration above (in much the same way as was done above for a Custom NavigationShield).

Sample Web Site

Follow the above instructions to configure the ChecksumNavigationShield. Pressing F5 and overtyping the query string should result in a UrlException.

Follow the above instructions to configure the SessionCrumbTrailPersister setting the maxLength to 0. Compare the URLs generated before and after this change, particularly the URL back to the Listing from the Details page.

Last edited Feb 15, 2014 at 4:20 PM by GrahamMendick, version 4