次のように、セキュリティ トリミングを備えたボグ標準のデフォルト サイトマップを使用する 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
内のへの呼び出しが気になります。BuildSiteMap
1 つの値を修正するためだけにすべてのデータを再帰的にメモリにプルするのは、私には間違っているように思えます。また、いつBuildSiteMap
呼び出されるかを制御することはできません。ノードデータが最初に必要になったときにオンデマンドで呼び出される、Attempt 1 のようなものをお勧めします。
試行 4 (新規) - 試行 2 と同様ですが、データの読み取りに関係するすべての仮想メンバー ( CurrentNode
、FindSiteMapNode
、FindSiteMapNodeFromKey
、GetChildNodes
、GetCurrentNodeAndHintAncestorNodes
、GetCurrentNodeAndHintNeighborhoodNodes
、GetParentNode
、)をオーバーライドしてGetParentNodeRelativeToCurrentNodeAndHintDownFromParent
、どこかで動的ノードの読み取りをインターセプトしようとします。GetParentNodeRelativeToNodeAndHintDownFromParent
HintAncestorNodes
HintNeighborhoodNodes
これはうまくいきませんでした。オーバーライドされたすべてのメンバーにデバッグ ステートメントを配置しましたが、ドロップダウン リストにデータをバインドするときに、それらのステートメントがまったく呼び出されないようです。BuildSiteMap
私が考えることができる唯一の説明は、呼び出し中にすべてのノードが一度にメモリに読み込まれるため、SiteMapNode
子ノードを列挙するときにプロバイダークラスにヒットしないということです。
誰にもより良い提案がありますか?