Adding QueryString Parameters to the SiteMapNode

There is no way to add querystring parameters to the SiteMapNode in a SiteMap control "out of the box." I'm quite surprised there is no option but luckily the SiteMap uses the provider model. After a Live search, I was able to find a solution provided by Bobby DeRosa. By creating a custom provider, this can be accomplished. The project I was on is an update of an ASP.net app written in VB.net so here is my VB.net port:

Imports System.Collections.Specialized
Imports System.Web

Namespace Configuration

    Public Class ExtendedSiteMapProvider
        Inherits XmlSiteMapProvider

        Public Overrides Sub Initialize(ByVal name As String, ByVal attributes As NameValueCollection)
            MyBase.Initialize(name, attributes)
            Dim resolveHandler As New SiteMapResolveEventHandler(AddressOf SmartSiteMapProvider_SiteMapResolve)
            AddHandler Me.SiteMapResolve, resolveHandler
        End Sub

        Function SmartSiteMapProvider_SiteMapResolve(ByVal sender As Object, ByVal e As SiteMapResolveEventArgs) As SiteMapNode
            If (SiteMap.CurrentNode Is Nothing) Then Return Nothing

            Dim this As New XmlSiteMapProvider
            Dim temp As SiteMapNode
            temp = SiteMap.CurrentNode.Clone(True)
            Dim u As Uri = New Uri(e.Context.Request.Url.ToString())
            Dim tempNode As SiteMapNode = temp

            While Not tempNode Is Nothing
                Dim qs As String = GetQueryString(tempNode, e.Context)
                If Not qs Is Nothing Then
                    If Not tempNode Is Nothing Then
                        tempNode.Url += qs
                    End If
                End If
                tempNode = tempNode.ParentNode
            End While

            Return temp
        End Function

        Private Function GetQueryString(ByVal node As SiteMapNode, ByVal context As HttpContext) As String
            If node("queryStringToInclude") Is Nothing Then Return Nothing

            Dim values As NameValueCollection = New NameValueCollection
            Dim vars() As String = node("queryStringToInclude").Split(",".ToCharArray())
            Dim s As String

            For Each s In vars
                Dim var As String = s.Trim()
                If context.Request.QueryString(var) Is Nothing Then Continue For
                values.Add(var, context.Request.QueryString(var))
            Next

            If values.Count = 0 Then Return Nothing

            Return NameValueCollectionToString(values)
        End Function

        Private Function NameValueCollectionToString(ByVal col As NameValueCollection) As String
            Dim parts(col.Count - 1) As String
            Dim keys() As String = col.AllKeys

            For i As Integer = 0 To keys.Length - 1
                parts(i) = keys(i) & "=" & col(keys(i))
            Next

            Dim url As String = "?" & String.Join("&", parts)

            Return url
        End Function

    End Class

End Namespace

I added the following to the web.config:

<siteMap defaultProvider="ExtendedSiteMapProvider" enabled="true">
    <providers>
        <clear />
        <add name="ExtendedSiteMapProvider" type="Configuration.ExtendedSiteMapProvider" siteMapFile="web.sitemap" securityTrimmingEnabled="true" />
    </providers>
</siteMap>

If I had a page of products on products.aspx, displayed the details of the product on details.aspx, and had a separate update.aspx page, my web.sitemap might look like this:

<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
    <siteMapNode url="~/" title="Main Page">
            <siteMapNode url="~/products.aspx" title="Products" >
                <siteMapNode url="~/details.aspx" title="Product Details" queryStringToInclude="ProductID" >
                    <siteMapNode url="~/update.aspx" title="Updating a Product" />
                </siteMapNode>
            </siteMapNode>
    </siteMapNode>
</siteMap>

So, on /update.aspx?ProductID=3, the SiteMapNode for Product Details would have a url of /details.aspx?ProductID=3.

Hopefully a similar feature will be added soon to the ASP.net SiteMap control.

Published Wednesday, June 04, 2008 11:46 PM by Jason N. Gaylord

Comments

# Adding QueryString Parameters to the SiteMapNode | videositemap.com

Pingback from  Adding QueryString Parameters to the SiteMapNode | videositemap.com

# re: Adding QueryString Parameters to the SiteMapNode

Thursday, June 05, 2008 4:09 AM by jagadeesh jupalli

Thank you, Very useful article :)

# Give Your Navigation Controls Querystring Parameters

Sunday, June 08, 2008 10:57 PM by The Rafael Van Dyke Blog

Give Your Navigation Controls Querystring Parameters

# re: Adding QueryString Parameters to the SiteMapNode

Tuesday, June 10, 2008 5:48 PM by marcus

Can you post the C# version ?

# derosa

Wednesday, June 11, 2008 7:22 AM by derosa

Pingback from  derosa

# a search box

Wednesday, June 11, 2008 7:25 AM by a search box

Pingback from  a search box

# re: Adding QueryString Parameters to the SiteMapNode

Monday, June 16, 2008 11:17 AM by Jason N. Gaylord

Marcus,

You can find the C# version below. I didn't test it, just did a quick conversion. Hope that helps!

Jason

*********************************************************

using System.Collections.Specialized;

using System.Web;

namespace Configuration

{

public class ExtendedSiteMapProvider : XmlSiteMapProvider

{

public override void Initialize(string name, NameValueCollection attributes)

{

base.Initialize(name, attributes);

SiteMapResolveEventHandler resolveHandler = new SiteMapResolveEventHandler(SmartSiteMapProvider_SiteMapResolve);

this.SiteMapResolve += resolveHandler;

}

SiteMapNode SmartSiteMapProvider_SiteMapResolve(object sender, SiteMapResolveEventArgs e)

{

if ((SiteMap.CurrentNode == null)) return null;

XmlSiteMapProvider @this = new XmlSiteMapProvider();

SiteMapNode temp;

temp = SiteMap.CurrentNode.Clone(true);

Uri u = new Uri(e.Context.Request.Url.ToString());

SiteMapNode tempNode = temp;

while (!tempNode == null) {

string qs = GetQueryString(tempNode, e.Context);

if (!qs == null)

{

if (!tempNode == null)

{

tempNode.Url += qs;

}

}

tempNode = tempNode.ParentNode;

}

return temp;

}

private string GetQueryString(SiteMapNode node, HttpContext context)

{

if (node("queryStringToInclude") == null) return null;

NameValueCollection values = new NameValueCollection();

string[] vars = node("queryStringToInclude").Split(",".ToCharArray());

string s;

foreach ( s in vars) {

string var = s.Trim();

if (context.Request.QueryString(var) == null) continue;

values.Add(var, context.Request.QueryString(var));

}

if (values.Count == 0) return null;

return NameValueCollectionToString(values);

}

private string NameValueCollectionToString(NameValueCollection col)

{

string[] parts = new string[col.Count - 1];

string[] keys = col.AllKeys;

for (int i = 0; i <= keys.Length - 1; i++) {

parts(i) = keys(i) + "=" + col(keys(i));

}

string url = "?" + string.Join("&", parts);

return url;

}

}

}

# re: Adding QueryString Parameters to the SiteMapNode

Friday, July 11, 2008 5:15 AM by DD

Hello.

First of all I want to thank you, for the article. For a long time I was searching for the solution and here I found it. I am using Sharepoint services and need to create breadcrumbs for my site. So I tryed to do all those thing described by the article:

I created dll with C# code put it to GAC, set web.config as in the egzample. An I still don't get needed parametres in url? Can you give me a hint?

# bobbie model

Friday, July 11, 2008 10:46 AM by bobbie model

Pingback from  bobbie model

# re: Adding QueryString Parameters to the SiteMapNode

Friday, July 18, 2008 1:17 AM by Dilip Nikam

We can do this way also. In this example I am showing how to add functionality of show-hide SubMenu, Enable-Disable User Click and AddQueryString.

<siteMapNode url="State/State.aspx#" IsClickAble="False" title="States" description="States" >    

     <siteMapNode url="State/State.aspx" AddQueryString="ID={0}" title="Create New State"  Visible="True" />

     <siteMapNode url="State/AllState.aspx"  title="All States"  Visible="True" />

     <siteMapNode url="State/StateMapping.aspx" title="State Field Mapping"  Visible="True" />

     <siteMapNode url="State/DeactivetedState.aspx" title="Deactiveted State"  Visible="False"/>

</siteMapNode>

protected void TopNavigationMenu_OnMenuItemDataBound(object sender, MenuEventArgs e)

   {

       SiteMapNode node = e.Item.DataItem as SiteMapNode;

       // check for the visible attribute and if false

       // remove the node from the parent

       // this allows nodes to appear in the SiteMapPath but not show on the menu

       if (!string.IsNullOrEmpty(node["Visible"]))

       {

           bool isVisible;

           if (bool.TryParse(node["Visible"], out isVisible))

           {

               if (!isVisible)

               {

                   e.Item.Parent.ChildItems.Remove(e.Item);

               }

           }

       }

       //Block User Click.

       if (!string.IsNullOrEmpty(node["IsClickAble"]))

       {

           e.Item.Selectable = false;

       }

       //Adding QueryString value In RunTime.

       if (!string.IsNullOrEmpty(node["AddQueryString"]))

       {

           e.Item.NavigateUrl = e.Item.NavigateUrl + "?" + node["AddQueryString"].ToString();

           string s = e.Item.NavigateUrl.ToString();

       }

   }

*~*~*~*~*~*~*~*~*~*~*

Dilip Nikam

dilipnikam@gmail.com

# bobbie model

Saturday, September 20, 2008 1:19 PM by bobbie model

Pingback from  bobbie model

# re: Adding QueryString Parameters to the SiteMapNode

Tuesday, October 21, 2008 6:14 PM by Rob

For those of you like me who just went ahead and created a class in the App_Code folder and get this error:

The provider 'SmartSiteMapProvider' specified for the defaultProvider does not exist in the providers collection

You need to change your webconfig file to this:

<siteMap defaultProvider="StoreSiteMap" enabled="true">

 <providers>

   <clear />

     <add name="StoreSiteMap" type="SmartSiteMapProvider" siteMapFile="~/Web.sitemap"/>

 </providers>

</siteMap>

Happy programming!

Rob

# re: Adding QueryString Parameters to the SiteMapNode

Friday, November 07, 2008 11:00 AM by Jeff Rausch

Jason,

Great job!  I took your C# code and had to make a few small changes to get it working correctly (on VS2008 & .NET 3.5 sp1):

#region Using Directives

using System.Collections.Specialized;

using System.Web;

#endregion

namespace Configuration

{

   public class ExtendedSiteMapProvider : XmlSiteMapProvider

   {

       public override void Initialize(string name, NameValueCollection attributes)

       {

           base.Initialize(name, attributes);

           this.SiteMapResolve += SmartSiteMapProvider_SiteMapResolve;

       }

       static SiteMapNode SmartSiteMapProvider_SiteMapResolve(object sender, SiteMapResolveEventArgs e)

       {

           if ((SiteMap.CurrentNode == null)) return null;

           SiteMapNode temp = SiteMap.CurrentNode.Clone(true);

           SiteMapNode tempNode = temp;

           while (tempNode != null)

           {

               string qs = GetQueryString(tempNode, e.Context);

               if (qs != null)

               {

                   tempNode.Url += qs;

               }

               tempNode = tempNode.ParentNode;

           }

           return temp;

       }

       private static string GetQueryString(SiteMapNode node, HttpContext context)

       {

           if (node["queryStringToInclude"] == null) return null;

           NameValueCollection values = new NameValueCollection();

           string[] vars = node["queryStringToInclude"].Split(",".ToCharArray());

           foreach (string s in vars)

           {

               string var = s.Trim();

               if (context.Request.QueryString[var] == null) continue;

               values.Add(var, context.Request.QueryString[var]);

           }

           if (values.Count == 0) return null;

           return NameValueCollectionToString(values);

       }

       private static string NameValueCollectionToString(NameValueCollection col)

       {

           string[] parts = new string[col.Count];

           string[] keys = col.AllKeys;

           for (int i = 0; i <= keys.Length - 1; i++)

           {

               parts[i] = keys[i] + "=" + col[keys[i]];

           }

           return "?" + string.Join("&", parts);

       }

   }

}

# re: Adding QueryString Parameters to the SiteMapNode

Thursday, November 27, 2008 10:31 PM by kiku maru

อยากได้โปรเจ็คตัวอย่างอ่ะ

if you have sample project plz upload for everyone

# re: Adding QueryString Parameters to the SiteMapNode

Friday, November 28, 2008 2:43 AM by Shuaib Badshah

Change your site map xml file at run time

# re: Adding QueryString Parameters to the SiteMapNode

Thursday, January 08, 2009 10:14 AM by Kostya

Nice approach, but, unfortunately, it does not work with SiteMapDataSource asp control.

# re: Adding QueryString Parameters to the SiteMapNode

Tuesday, March 10, 2009 10:33 AM by Citra

It was really helpful information. Thanks.

# re: Adding QueryString Parameters to the SiteMapNode

Wednesday, March 11, 2009 1:19 PM by Hassan Voyeau

this is what I did

haveworld.blogspot.com/.../aspnet-include-querystring-parameters.html

Leave a Comment

(required) 
(required) 
(optional)
(required)