So, I was asked to add a link to an external Web Site from the Main Menu of our app and to display it in a new browser window.
The Main Menu is composed of SiteMapNodeInfo nodes that are consumed by a custom SiteMapProvider derived from StaticSiteMapProvider and eventually fed to a TreeView for rendering.
Using the principles of Orangutan-Driven Development I sledgehammered the code with a blunt instrument to see what would fall out the tree. Thus:
SiteMapNodeInfo cityScopeNode = new SiteMapNodeInfo("Links", "http://CityScope.com", "Links");
siteMapBuilderService.AddNode(cityScopeLinkNode, Globals.RuleNames.ExternalLinks, 3);
..and was duly greeted with the System.Web.HttpException and message “http://CityScope.com not a valid virtual path” (no bananas).
The bulk of my problem was solved by Joe Audette who showed me that the URL in the SiteMapInfo node must be a path that resides within the application, the validation for this being the .NET Framework call:
System.Web.StaticSiteMapProvider.AddNode(SiteMapNode node, SiteMapNode parentNode)
Deep within my Reptilian Brain Stem, inchoate impulses began to coagulate: SiteMap…Site…yeeessss…in-TER-naaaaaallll. Fair enough, since its a SiteMap then external Links are probably contra-indicated, but it IS nevetheless possible to include an external link when using a SiteMapProvider, by kind of sneaking around it.
Joe pretty much gave me the solution by referring to the MenuItemDataBound event of his Menu Control and explaining that “AFTER the SiteMapNode is in the nodes collection you can get away with changing the Url to an external link.”
I didn’t have a Menu control, but I did have a TreeView – ergo:
Step 1: Initialize SiteMapNode to something that passes the AddNode validation – an empty string will do.
Step 2: Handle the TreeView’s TreeNodeDataBound event to set the Node’s URL to an external link.
Step 3: Set the SiteMapNode’s ‘Target’ property to “_blank” if you want the external Link displayed in a new browser window.
From our Web Client Software Factory ModuleInitializer :
protected virtual void RegisterSiteMapInformation(ISiteMapBuilderService siteMapBuilderService)
SiteMapNodeInfo LinksRootNode =
new SiteMapNodeInfo(LinkNames.Links.Name, LinkNames.Links.URL, LinkNames.Links.Name, "");
// Put string.Empty in place of external Link to avoid HttpException SiteMapNodeInfo CityScopeNode =
new SiteMapNodeInfo(LinkNames.CityScope.Name, string.Empty, LinkNames.CityScope.Name);
In our MasterPage where the TreeView is rendered:
protected void TreeView_TreeNodeDataBound(object sender, TreeNodeEventArgs e)
// Initialise the CityScope Link (which is external)
// and display it in a new browser window when selected
if (e.Node.Text == LinkNames.CityScope.Name)
e.Node.NavigateUrl = "http://CityScope.com.au";
e.Node.Target = "_blank";
Life Energy Consumed: 41 mins.
Thanks to Scott Berkun for the inspiration for ODD