Muchas son las veces que hemos detecado que el SiteMap que nos ofrece Microsoft, se nos queda corto cuando deseamos crear dinamismos en función de variables, como podría ser un QueryString o un varible de sessión.
En este post, vamos a descubrir como crear un SiteMap customizable en función de varias variables, en nuestro ejemplo utilizaremos una QueryString.
Imaginemos que queremos cambiar el título de un nodo, en función de su QueryString como en este caso:
<siteMapNode title="Departamentos" url="~/Dpto/Default.aspx" >
<siteMapNode title="Nuevo Departamento" editTitle="Editar Departamento" url="~/Dpto/Dpto.aspx" queryStringToInclude="EntId" ></siteMapNode>
</siteMapNode>
Como vemos en este ejemplo, queremos cambiar el nodo de Nuevo Departamento en función del QueryString en el caso que exista EntId para que quede de la siguiente manera
Departamentos > Nuevo Departamento
o
Departamentos > Editar Departamento
En primer lugar, crearemos un proyecto de Biblioteca de clases que lo llamaremos ExtendedSiteMapProvider donde crearemos el siguiente código
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
tempNode.Title = tempNode("editTitle")
Return tempNode
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
Si nos fijamos, utilizamos el método
GetQueryString que nos evaluará si existe el atributo
queryStringToInclude del nodo y si existe, nos validará que esté informado ese atributo en el QueryString.
Ya por último, nos queda por decirle a nuestro Web.Config que utilize nuestro proveedor de SiteMap en lugar del estándar de Microsoft.
Para ello pondremos en nuestro web.config lo siguiente
<siteMap defaultProvider="ExtendedSiteMapProvider" enabled="true">
<providers>
<clear />
<add name="ExtendedSiteMapProvider" type="OpenSky.UI.Utils.Configuration.ExtendedSiteMapProvider" siteMapFile="web.sitemap" securityTrimmingEnabled="true" />
</providers>
</siteMap>