4

次のように、セキュリティ トリミングを備えたボグ標準のデフォルト サイトマップを使用する Web サイトがあります。

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

Titleすべて順調ですが、いくつかのバックエンド基準に基づいて 1 つのノードの を変更する要求が来ました。単純なことのように聞こえますが、明らかにそうではありません。

試行 1 -SiteMapResolveイベントの処理。このイベントがどこで処理されるかは問題ではないようです。それを示したGlobal.asaxのは、それが私が試した場所の 1 つであり、機能したからです。

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

これは、関連するページに移動したときに問題なく機能しましたが、残念ながら、サイト ナビゲーションの一部には、次のようにサイト マップにデータ バインドされたコンボ ボックスが含まれます。

<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" />

このメニューがレンダリングされるときSiteMapResolve、現在のノードはメニューが定義されているページであるため、どのコンテンツに対してもイベントは発生しません。その結果、メニューには、正しいタイトルではなく、物理的なサイトマップ ファイルからの無意味なプレースホルダー タイトルが表示されます。

試行 2 - 独自のサイトマップ プロバイダーを作成します。デフォルトの動作をすべて複製したくなかったので、次のようにデフォルトのプロバイダーから派生させてみました。

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

GetChildNodesサイトをナビゲートするときにあまり頻繁に呼び出されないように見えるため、これは機能しません。

試行 3 - データがアクセスされたときではなく、メモリに読み込まれた直後にデータを修正してみてください。

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

これはうまくいくようです。ただ、メソッドGetAllNodes内のへの呼び出しが気になります。BuildSiteMap1 つの値を修正するためだけにすべてのデータを再帰的にメモリにプルするのは、私には間違っているように思えます。また、いつBuildSiteMap呼び出されるかを制御することはできません。ノードデータが最初に必要になったときにオンデマンドで呼び出される、Attempt 1 のようなものをお勧めします。

試行 4 (新規) - 試行 2 と同様ですが、データの読み取りに関係するすべての仮想メンバー ( CurrentNodeFindSiteMapNodeFindSiteMapNodeFromKeyGetChildNodesGetCurrentNodeAndHintAncestorNodesGetCurrentNodeAndHintNeighborhoodNodesGetParentNode、)をオーバーライドしてGetParentNodeRelativeToCurrentNodeAndHintDownFromParent、どこかで動的ノードの読み取りをインターセプトしようとします。GetParentNodeRelativeToNodeAndHintDownFromParentHintAncestorNodesHintNeighborhoodNodes

これはうまくいきませんでした。オーバーライドされたすべてのメンバーにデバッグ ステートメントを配置しましたが、ドロップダウン リストにデータをバインドするときに、それらのステートメントがまったく呼び出されないようです。BuildSiteMap私が考えることができる唯一の説明は、呼び出し中にすべてのノードが一度にメモリに読み込まれるため、SiteMapNode子ノードを列挙するときにプロバイダークラスにヒットしないということです。

誰にもより良い提案がありますか?

4

4 に答える 4

2

カスタムSiteMapProviderでは、BuildSiteMapメソッドをオーバーライドし、SiteMapNodesを手動で作成します。カスタムプロパティを変更および/または追加するには、NameValueCollectionを作成してSiteMapNodeにカスタム属性を追加し、これをSiteMapNodeコンストラクターに渡します。

于 2009-10-26T12:51:45.923 に答える
1

調査をしてくれたクリスチャンに感謝します。あなたの結果を使用して、私は他の人を助けることができる次のことを考え出しました:

' 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
于 2011-12-16T18:21:54.227 に答える
1

試行 2 にかなり近づいています。GetParentNodeFindSiteMapNodeもオーバーライドする必要があります。

于 2009-10-26T12:39:46.057 に答える
1

提案をしてくれた Mark と Rex に感謝します。私がやったことは、サイトマッププロバイダーをそのままにして、マスターページの1つのノードを修正することでした。

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

ただし、マークの回答を受け入れました。将来、より広範な変更を行う必要があることが判明した場合は、そのようにするためです。

于 2009-11-09T08:56:05.953 に答える