none
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:

    Group>Family>Genera>Species>Details

    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" 
    
    
    
                    RenderCurrentNodeAsLink="true">
    
    
    
                <PathSeparatorStyle Font-Bold="False" ForeColor="Black" />
    
    
    
                <RootNodeStyle Font-Size="140%" ForeColor="Black"/>
    
    
    
                <CurrentNodeStyle ForeColor="Black" Font-Size="110%"/>
    
    
    
                <NodeStyle ForeColor="Black" Font-Size="110%"/>
    
            </asp:SiteMapPath>
    
    
    
    
    SiteMap:
    
    
    
    <siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
    
    	<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"/>
    
    				</siteMapNode>
    
    
    
    			</siteMapNode>
    
    
    
    		  </siteMapNode>
    
    
    
    		</siteMapNode>
    
    </siteMap>
    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: http://www.csharper.net/blog/sitemapprovider_doesn_t_take_querystring_into_consideration.aspx)

    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;

            RemoveQuery(SiteMap.RootNode);

            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)
            {
                RemoveQuery(child);
            }
        }

        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)
                    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];
          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">
    
    			<providers>
    
    				<clear />
    
    				<add name="SmartSiteMapProvider" type="SmartSiteMapProvider" siteMapFile="web.sitemap" securityTrimmingEnabled="true" />
    
    		         </providers>
    
    		</siteMap>

    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)

    http://test.com/plants/genera.aspx?family_name=Acanthaceae?family_name=Acanthaceae?family_name=Acanthaceae?family_name=Acanthaceae

    it shoule be

    http://test.com/plants/genera.aspx?family_name=Acanthaceae 

    Do you have any suggestion ??

    Any help is highly appreciated.

    Thanks

    • 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: http://forums.asp.net/

    Wednesday, April 14, 2010 1:34 AM
  • Thanks BinaryCoder. I also asked this question to asp.net forums: http://forums.asp.net/p/1546936/3787013.aspx#3787013

    Finally, it works now. Thanks

     


    Rajendra
    Thursday, April 15, 2010 4:27 PM