SiteMap Provider and QueryString isssue ASP.NET C# RRS feed

  • Question

  • Hi,

    I am working in a web apps where there are 4 tables with one-to-many relations.

    Group has one to many relation with family,

    family has one to many relation with Genera,

    Genera has one to many relation with species

    I need this kind of breadcrumbs:


    Let say, I am at Details page and when click Genera it should display the Genera of that datails page so on...

    Here is my code in header.ascx:

     <asp:SiteMapPath ID="SiteMapPath1" runat="server" Enabled="true" EnableViewState="true"
                    Font-Size="110%" PathSeparator=" > " PathDirection="RootToCurrent" 
                <PathSeparatorStyle Font-Bold="False" ForeColor="Black" />
                <RootNodeStyle Font-Size="140%" ForeColor="Black"/>
                <CurrentNodeStyle ForeColor="Black" Font-Size="110%"/>
                <NodeStyle ForeColor="Black" Font-Size="110%"/>
    <siteMap xmlns="" >
    	<siteMapNode title="Group">
    		<siteMapNode url="~/FamilyMatches.aspx" title="Family" roles="GeneralRole" reliantOn="Group_name">
    			<siteMapNode url="~/GeneraMatches.aspx" title="Genera" roles="GeneralRole" reliantOn="family_name" >
    			<siteMapNode url="~/SpeciesMatches.aspx" title="Species" roles="GeneralRole" reliantOn="genus_name">
    					<siteMapNode title="Detail" url="~/DetailsPage.aspx" reliantOn="Species_id"/>
    Then at the every aspx page where I need breadcrumbs i use this:
    <%@ Register Src="header.ascx" TagName="header" TagPrefix="uc1" %>
    <uc1:header ID="Header1" runat="server" />  

    Now, the error is:

    "Object reference not set to an instance of an object"(it points to the querystring of the page) 

    Then I created a class SmartSiteMapProviders.cs (according to this link:

    public class SmartSiteMapProvider : XmlSiteMapProvider

        public override void Initialize(string name, NameValueCollection attributes)

            base.Initialize(name, attributes);

            this.SiteMapResolve += new SiteMapResolveEventHandler(SmartSiteMapProvider_SiteMapResolve);


        SiteMapNode SmartSiteMapProvider_SiteMapResolve(object sender, SiteMapResolveEventArgs e)

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


            SiteMapNode tempNode = SiteMap.CurrentNode;

            while (tempNode != null)

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

                if (qs != null)

                     tempNode.ReadOnly = false;
                    tempNode.Url += qs;
                    tempNode.ReadOnly = true;

                tempNode = tempNode.ParentNode;
            return SiteMap.CurrentNode;

       private void RemoveQuery(SiteMapNode parent)
            int pos = parent.Url.IndexOf('?');

            if (pos != -1)
                parent.ReadOnly = false;
                parent.Url = parent.Url.Remove(pos);
                parent.ReadOnly = true;

            foreach (SiteMapNode child in parent.ChildNodes)

        private string GetReliance(SiteMapNode node, HttpContext context)

        {   //Check to see if the node supports reliance
            if (node["reliantOn"] == null)
                return null;
            NameValueCollection values = new NameValueCollection();
            string[] vars = node["reliantOn"].Split(",".ToCharArray());
            foreach (string s in vars)

              string var = s.Trim();
                //Make sure the var exists in the querystring
                if (context.Request.QueryString[var] == null)
                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];
          string[] keys = col.AllKeys;
            for (int i = 0; i < keys.Length; i++)
               parts[i] = keys[i] + "=" + col[keys[i]];
               string url = "?" + String.Join("&", parts);

            return url;

    and use at web.config file like:

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

    Now, the problem is:

    when I come back from details page to family/species it takes the repeated querystring in URL(when I debug this issue, it takes this repeated value in the upper NameValueCollectionToString method)

    it shoule be 

    Do you have any suggestion ??

    Any help is highly appreciated.


    • Moved by SamAgain Wednesday, April 14, 2010 3:11 AM (From:.NET Base Class Library)
    Tuesday, April 13, 2010 8:59 PM

All replies

  • I haven't looked at this in detail, but the following looks like it could be the problem:

           tempNode.ReadOnly = false;
                    tempNode.Url += qs;
                    tempNode.ReadOnly = true;

    I am guessing that it keeps adding on more ?family_name=___ parts regardless of what is already in the Url from a previous run.  Put a breakpoint in there and keep an eye on what happens to tempNode.Url.

    That being said, mutating SiteMapNodes is a bad idea.  The web site, and hence a single SiteMapNode, might be accessed by multiple threads.  You don't want to be changing the node while there is a possiblility of it being accessed by another thread.  A main reason for the ReadOnly property is to keep this from happening, but you defeated that safeguard.  I think the simplest remedy for this would be to replace the editing of the existing SiteMapNode with the construction of a new SiteMapNode.

    Note the ASP.NET has its own separate forums.  For best answers regarding ASP.NET, post to:

    Wednesday, April 14, 2010 1:34 AM
  • Thanks BinaryCoder. I also asked this question to forums:

    Finally, it works now. Thanks


    Thursday, April 15, 2010 4:27 PM