<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://weblogs.asp.net/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Alessandro Zifiglio : SiteMapNode</title><link>http://weblogs.asp.net/alessandro/archive/tags/SiteMapNode/default.aspx</link><description>Tags: SiteMapNode</description><dc:language>en</dc:language><generator>CommunityServer 2007 SP1 (Build: 20510.895)</generator><item><title>SiteMapPath Control and dynamic url based on querystring.</title><link>http://weblogs.asp.net/alessandro/archive/2007/09/30/sitemappath-control-and-dynamic-url-based-on-querystring.aspx</link><pubDate>Sun, 30 Sep 2007 23:11:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:4260899</guid><dc:creator>alessandro</dc:creator><author>alessandro</author><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/alessandro/rsscomments.aspx?PostID=4260899</wfw:commentRss><comments>http://weblogs.asp.net/alessandro/archive/2007/09/30/sitemappath-control-and-dynamic-url-based-on-querystring.aspx#comments</comments><description>&lt;P&gt;The SiteMapPath control is really great. If you need breadcrumbs, eg a trail left based on the depth of the pages, this is absolutely a great control. However all is nice when the navigation is defined in your sitemap, this means static url's. But what if you have a dynamic url, maybe its based on querystring's and you want to leave a trail. There is some help in the msdn documentation regarding this, however its not very clear. The reference I am talking about is&amp;nbsp;: &lt;/P&gt;
&lt;P&gt;&lt;A href="http://msdn2.microsoft.com/en-us/library/system.web.sitemap.sitemapresolve.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/system.web.sitemap.sitemapresolve.aspx"&gt;http://msdn2.microsoft.com/en-us/library/system.web.sitemap.sitemapresolve.aspx&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;As you can see from the above documentation material, it tells you that if you need this type of functionality then you need to subscribe to the SiteMapResolve event handler of your sitemap. "This event is raised when the CurrentNode property is accessed. This enables the user to implement custom logic when creating a SiteMapNode representation of the currently executing page without requiring a custom provider implementation." &lt;/P&gt;
&lt;P&gt;All good, except I think this event could be documented better. To be honest, I saw the sample code provided with the documentation, and it took a bit of experimentation to actually get it to work the way I wanted. Imagine a simple scenario where you have an initial home page, then two pages within the same physical directory, so to simplify lets look at an example sitemap : &lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:efd9e659-408a-4c99-845c-178a37d3a337 contentEditable=false style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE style="BACKGROUND-COLOR: white"&gt;&lt;DIV&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;lt;?&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(255,0,255)"&gt;xml version="1.0" encoding="utf-8" &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;?&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;
&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(128,0,0)"&gt;siteMap &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(255,0,0)"&gt;xmlns&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0"&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(255,0,0)"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;
    &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(128,0,0)"&gt;siteMapNode &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(255,0,0)"&gt;url&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;="~/Default.aspx"&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(255,0,0)"&gt; title&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;="Home"&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;
      &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(128,0,0)"&gt;siteMapNode &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(255,0,0)"&gt;url&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;="~/list.aspx"&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(255,0,0)"&gt; title&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;="List items"&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(255,0,0)"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;/&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;
      &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(128,0,0)"&gt;siteMapNode &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(255,0,0)"&gt;url&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;="~/details.aspx"&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(255,0,0)"&gt; title&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;="Details page"&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(255,0,0)"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;/&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;
    &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(128,0,0)"&gt;siteMapNode&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;
&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(128,0,0)"&gt;siteMap&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;gt;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;/PRE&gt;&lt;/DIV&gt;Now as you can see, i have 3 pages : 
&lt;OL&gt;
&lt;LI&gt;Default.aspx = Home page&lt;/LI&gt;
&lt;LI&gt;list.aspx&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = List items&lt;/LI&gt;
&lt;LI&gt;details.aspx&amp;nbsp; = Details of each item in the list page.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Now, this is what is going to happen. On default page, i have a link to List.aspx ; List.aspx just displays a list of items and clicking an item in the list should display details on the item. To do this we will be passing the item id in the querystring. This means the parent/child relationship btw list.aspx and details.aspx is a logical relationship, which is related by the id we will be passing in the querystring. For this type of relationships a) The SiteMapPath wont pick it up, and define a trail, if we do not nest details.aspx in list.aspx, b) The value we will be passing in the querystring is dynamic and in the sitemap we can only define static url's. Its too bad the sitemap supports localization expressions but not inline codeblocks, a pity and a limitation you have to live with. &lt;/P&gt;
&lt;P&gt;So knowing these two things, we can start by redefining our site to&amp;nbsp;satisfy with the above requirement&amp;nbsp;a) : &lt;/P&gt;
&lt;DIV class=wlWriterSmartContent id=57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:4f02c983-2944-4cb2-b691-6b424772ab52 contentEditable=false style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE style="BACKGROUND-COLOR: white"&gt;&lt;DIV&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;lt;?&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(255,0,255)"&gt;xml version="1.0" encoding="utf-8" &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;?&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;
&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(128,0,0)"&gt;siteMap &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(255,0,0)"&gt;xmlns&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0"&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(255,0,0)"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;
    &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(128,0,0)"&gt;siteMapNode &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(255,0,0)"&gt;url&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;="~/Default.aspx"&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(255,0,0)"&gt; title&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;="Home"&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;
      &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(128,0,0)"&gt;siteMapNode &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(255,0,0)"&gt;url&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;="~/list.aspx"&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(255,0,0)"&gt; title&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;="List items"&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;
        &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(128,0,0)"&gt;siteMapNode &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(255,0,0)"&gt;url&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;="~/details.aspx"&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(255,0,0)"&gt; title&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;="Details page"&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(255,0,0)"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;/&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;
      &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(128,0,0)"&gt;siteMapNode&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;
    &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(128,0,0)"&gt;siteMapNode&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;
&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(128,0,0)"&gt;siteMap&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;
&lt;/SPAN&gt;&lt;/DIV&gt;&lt;/PRE&gt;&lt;/DIV&gt;Note how the details siteMapNode is nested in list ; now because of this nesting structure it will build us a nice breadcrumb trail as we keep going from home, to list and then to details as : home &amp;gt; List items &amp;gt; Details page : so this happened for us automatically. One problem remains however. Note how the url for the siteMapNode details page is static. It does not include the querystring. The querystring is defined at runtime dynamically, so in order to fix this, lets subscribe to the SiteMapResolve event of our sitemap as suggested by the documentation on msdn. We will be doing this in details.aspx as in the example that follows below : 
&lt;DIV class=wlWriterSmartContent id=57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:d6cfb6dc-8013-474c-ad14-2fa0bd24a4dc contentEditable=false style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; FLOAT: none; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px"&gt;&lt;PRE style="BACKGROUND-COLOR: white"&gt;&lt;DIV&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;protected&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;void&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt; Page_Load(&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;object&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt; sender, EventArgs e)
    {
        SiteMap.SiteMapResolve &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;+=&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;
          &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;new&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt; SiteMapResolveEventHandler(SiteMap_SiteMapResolve);
    }

    &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;private&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt; SiteMapNode SiteMap_SiteMapResolve(Object sender, SiteMapResolveEventArgs e)
    {
        SiteMapNode currentNode &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;=&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt; SiteMap.CurrentNode.Clone(&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;true&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;);
        &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;string&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt; currentRequest &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;=&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt; e.Context.Request.Url.PathAndQuery;
        &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;if&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt; (currentNode.ParentNode &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;!=&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;null&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;)
            currentNode.ParentNode.Url &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;=&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt; currentRequest;

    &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,128,0)"&gt;//&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,128,0)"&gt; now return the currentNode after we modified the parentNode
    &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,128,0)"&gt;//&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,128,0)"&gt; supply it the new url which includes the querystring value.&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,128,0)"&gt;
&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt;        &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;return&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,0,0)"&gt; currentNode; 
    }&lt;/SPAN&gt;&lt;/DIV&gt;&lt;/PRE&gt;&lt;/DIV&gt;Some things to take note here is, we are cloning the currentNode, the reason to do this is because by default we have a readonly in memory copy. Cloning the node while passing true to the clone argument allows us to clone all parent and ancestor nodes of the current node. A deep clone like this is essential because it allows us to walk down parents/children in the currentnode. For eg, in our example code above, what we want to do is modify the url of the parent page of the current details page where the code is executing. In this way we can modify the url to include the querystring we wanted. 
&lt;P&gt;Another thing you want to be careful about when using SiteMapResolve method is that by default it uses aggressive caching, and so, some changes wont be visible unless there has been a file change in your application or someone touched web.config ; so during development, when you make some changes to your code in SiteMapResolve event and the changes are not being picked up, you might want to touch web.config which should recycle the appdomain and clear the cache.&lt;/P&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=4260899" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/alessandro/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/alessandro/archive/tags/SiteMap/default.aspx">SiteMap</category><category domain="http://weblogs.asp.net/alessandro/archive/tags/SiteMapNode/default.aspx">SiteMapNode</category><category domain="http://weblogs.asp.net/alessandro/archive/tags/SiteMapPath/default.aspx">SiteMapPath</category></item></channel></rss>