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.
<span style="font-weight:bold;">C#:</span>
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);
}
}
}
1 comment:
Thank You, Excelent
Post a Comment