Frage

Wir haben eine Website, auf der ein Sitemap mit einem Sitemap mit einer Sitemap mit Sicherheit verwendet wird, wie folgt:

<siteMap defaultProvider="default" enabled="true">
  <providers>
    <add siteMapFile="~/Web.sitemap" securityTrimmingEnabled="true" name="default" type="System.Web.XmlSiteMapProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
  </providers>
</siteMap>

Alles sehr gut, aber es ist eine Anfrage eingegangen, um die zu ändern Title eines Knotens basierend auf einigen Back-End-Kriterien. Klingt nach einer einfachen Sache, aber anscheinend nicht.

Versuch 1 - Umgang mit dem SiteMapResolve Veranstaltung. Es scheint keine Rolle zu spielen wo Diese Veranstaltung wird behandelt, ich habe es gezeigt Global.asax Nur weil das einer der Orte war, an denen ich es ausprobiert habe und es hat funktioniert.

Public Class Global_asax
    Inherits System.Web.HttpApplication

    Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
        AddHandler SiteMap.SiteMapResolve, AddressOf SiteMapResolve
    End Sub

    Sub Application_EndRequest(ByVal sender As Object, ByVal e As EventArgs)
        RemoveHandler SiteMap.SiteMapResolve, AddressOf SiteMapResolve
    End Sub

    Private Shared Function SiteMapResolve(ByVal sender As Object, ByVal e As SiteMapResolveEventArgs) As SiteMapNode

        Dim node As SiteMapNode = SiteMap.CurrentNode
        If IsThisTheNodeToChange(node) Then
            node = node.Clone()
            node.Title = GetNodeTitle()
        End If
        Return node

    End Function

End Class

Dies funktionierte gut, wenn die entsprechende Seite navigiert wurde, aber leider ist ein Teil der Site-Navigation ein Kombinationsfeld, das auf der Site-Karte wie folgt auf Daten gebunden ist:

<asp:SiteMapDataSource ID="siteMapDataSource" runat="Server" ShowStartingNode="false" StartFromCurrentNode="false" StartingNodeOffset="1" />
<asp:DropDownList ID="pageMenu" runat="Server" AutoPostBack="True" DataSourceID="siteMapDataSource" DataTextField="Title" DataValueField="Url" />

Wenn dieses Menü gerendert wird, die SiteMapResolve Das Ereignis feuert keinen der Inhalte aus, da der aktuelle Knoten die Seite ist, auf der das Menü definiert ist. Infolgedessen zeigt das Menü eher den Nonsense -Platzhaltertitel aus der physischen Sitemap -Datei als den richtigen Titel.

Versuch 2 - Schreiben Sie meinen eigenen Sitemap -Anbieter. Ich wollte nicht das gesamte Standardverhalten duplizieren, also habe ich versucht, vom Standardanbieter wie folgt abzuleiten.

Public Class DynamicXmlSiteMapProvider
    Inherits XmlSiteMapProvider

    Private _dataFixedUp As Boolean = False

    Public Overrides Function GetChildNodes(ByVal node As SiteMapNode) As SiteMapNodeCollection

        Dim result As SiteMapNodeCollection = MyBase.GetChildNodes(node)
        If Not _dataFixedUp Then
            For Each childNode As SiteMapNode In result
                FixUpNode(childNode)
            Next
        End If
        Return result

    End Function

    Private Sub FixUpNode(ByVal node As SiteMapNode)

        If IsThisTheNodeToChange(node) Then
            node.ReadOnly = False
            node.Title = GetNodeTitle()
            node.ReadOnly = True
            _dataFixedUp = True
        End If

    End Sub

End Class

Das funktioniert nicht, weil GetChildNodes Es scheint nicht sehr oft aufgerufen zu werden, wenn man auf der Website navigiert.

Versuch 3 - Versuchen Sie, die Daten unmittelbar nach dem geladenen Speicher in den Speicher zu beheben, anstatt wenn sie zugegriffen werden.

Public Class DynamicXmlSiteMapProvider
    Inherits XmlSiteMapProvider

    Private _dataFixInProgress As Boolean = False
    Private _dataFixDone As Boolean = False

    Public Overrides Function BuildSiteMap() As SiteMapNode

        Dim result As SiteMapNode = MyBase.BuildSiteMap()
        If Not _dataFixInProgress AndAlso Not _dataFixDone Then
            _dataFixInProgress = True
            For Each childNode As SiteMapNode In result.GetAllNodes()
                FixUpNode(childNode)
            Next
            _dataFixInProgress = False
            _dataFixDone = True
        End If
        Return result

    End Function

    Private Sub FixUpNode(ByVal node As SiteMapNode)

        If IsThisTheNodeToChange(node) Then
            node.ReadOnly = False
            node.Title = GetNodeTitle()
            node.ReadOnly = True
        End If

    End Sub

End Class

Dies scheint zu funktionieren. Ich mache mir jedoch Sorgen um den Anruf an GetAllNodes in dem BuildSiteMap Methode. Es scheint mir einfach falsch zu sein, alle Daten rekursiv in den Speicher zu bringen, um einen Wert zu reparieren. Außerdem habe ich keine Kontrolle darüber, wann BuildSiteMap wird genannt. Ich würde etwas mehr wie Versuch 1 bevorzugen, das auf Anfrage bezeichnet wird, wenn die Knotendaten zuerst erforderlich sind.

Versuch 4 (neu) - Wie Versuch 2, aber überschreibend alle Virtuelle Mitglieder, die mit Lesen von Daten zu tun haben (DatenCurrentNode, FindSiteMapNode, FindSiteMapNodeFromKey, GetChildNodes, GetCurrentNodeAndHintAncestorNodes, GetCurrentNodeAndHintNeighborhoodNodes, GetParentNode, GetParentNodeRelativeToCurrentNodeAndHintDownFromParent, GetParentNodeRelativeToNodeAndHintDownFromParent, HintAncestorNodes, HintNeighborhoodNodes), um zu versuchen, das Lesen des dynamischen Knotens irgendwo abzufangen.

Das hat nicht funktioniert. Ich habe Debug -Aussagen in alle überschriebenen Mitglieder eingerichtet, und es scheint, dass keiner von ihnen aufgerufen wird, wenn Daten an die Dropdown -Liste gebunden sind. Die einzige Erklärung, an die ich denken kann BuildSiteMap anrufen, damit die SiteMapNode trifft nicht auf die Anbieterklasse, wenn Kinderknoten aufgezählt werden.

Hat jemand bessere Vorschläge?

War es hilfreich?

Lösung

In unserem benutzerdefinierten Sitemapprovider überschreiben wir die BuildSitemap -Methode und konstruieren die Sitemapnodes manuell. So ändern Sie und/oder hinzuzufügen benutzerdefinierte Eigenschaften, wir fügen den Sitemapnodes benutzerdefinierte Attribute hinzu, indem wir eine NameValueCollection erstellen und diese zum Sitemapnode -Konstruktor hinzufügen.

Andere Tipps

Sie sind mit Versuch Nr. 2 ziemlich nahe - Sie müssen auch auch außer Kraft setzen GetParentnode und FindSitemapnode auch.

Vielen Dank an Mark und Rex für die Vorschläge. Was ich am Ende gemacht habe, war, den Sitemap -Anbieter in Ruhe zu lassen und nur den einen Knoten auf der Masterseite zu reparieren, also:

Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init

    ' Do this as early as possible in the page lifecycle so that it happens before any
    ' automatic data binding or control initialisation is done.
    Dim node As SiteMapNode = GetNodeToEdit()
    Dim nodeReadOnly As Boolean = node.ReadOnly
    node.ReadOnly = False
    node.Title = GetNodeTitle()
    node.ReadOnly = nodeReadOnly

End Sub

Ich habe jedoch Marks Antwort angenommen, denn so werde ich es tun, wenn sich herausstellt, dass umfangreichere Änderungen in Zukunft vorgenommen werden müssen.

Danke Christian für deine Forschung. Mit Ihren Ergebnissen habe ich das Folgende ausgedacht, das anderen helfen kann:

' Dynamically update some menu items.
'
' Since the correct Medical Center ID is not known until runtime, need to
' append "&MEDICAL_CENTER_ID=xxx" to all of the report's URLs in Web.sitemap.
Public Shared Sub UpdateMenu(ByVal MedicalCenterID As String)
  Dim CurrentNodeTitle As String = ""
  Dim NodeReadOnlyProperty As Boolean

  ' Home menu item
  CurrentNodeTitle = SiteMap.CurrentNode.Title

  ' Determines if the current node has child nodes.
  If (SiteMap.CurrentNode.HasChildNodes) Then
    ' Loop through top level 1 menu items (looking for Reports)
    For Each ChildNodesEnumerator1 As SiteMapNode In SiteMap.CurrentNode.ChildNodes
      CurrentNodeTitle = ChildNodesEnumerator1.Title
      If CurrentNodeTitle = "Reports" Then
        ' Loop through level 2 menu items (looking for specfic reports)
        For Each ChildNodesEnumerator2 As SiteMapNode In ChildNodesEnumerator1.ChildNodes
          CurrentNodeTitle = ChildNodesEnumerator2.Title
          If CurrentNodeTitle = "Multi-Day Vehicle Requests" Or _
           CurrentNodeTitle = "XXXXXXXXXXXXXXXXX" Then
            ' First check if the URL has not been modified already
            If InStr(ChildNodesEnumerator2.Url, "MEDICAL_CENTER_ID") = 0 Then
              NodeReadOnlyProperty = ChildNodesEnumerator2.ReadOnly
              ChildNodesEnumerator2.ReadOnly = False
              ChildNodesEnumerator2.Url = ChildNodesEnumerator2.Url & "&MEDICAL_CENTER_ID=" & MedicalCenterID
              ChildNodesEnumerator2.ReadOnly = NodeReadOnlyProperty
            End If
          End If
        Next
      End If
    Next
  End If
End Sub
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top