سؤال

لدينا موقع ويب يستخدم خريطة Sitemap الافتراضية المعيارية مع تقليص الأمان على النحو التالي:

<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 - التعامل مع SiteMapResolve حدث. لا يبدو أنه مهم أين يتم التعامل مع هذا الحدث ، لقد أظهرته في Global.asax لمجرد أن ذلك كان أحد الأماكن التي جربتها وعملت.

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 لا يطلق الحدث أي من المحتويات لأن العقدة الحالية هي الصفحة التي يتم تحديد القائمة عليها. نتيجة لذلك ، تعرض القائمة عنوان العنصر النائم الهراء من ملف Sitemap المادي بدلاً من العنوان الصحيح.

محاولة 2 - كتابة مزود خريطة sitemap الخاصة بي. لم أكن أرغب في تكرار كل السلوك الافتراضي ، لذلك حاولت اشتقاق من الموفر الافتراضي على النحو التالي.

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 طريقة. يبدو أنه من الخطأ بالنسبة لي سحب جميع البيانات بشكل متكرر إلى الذاكرة فقط لإصلاح قيمة واحدة. أيضا ، ليس لدي أي سيطرة على متى BuildSiteMap يسمى. أفضل شيء يشبه المحاولة 1 ، والذي يسمى الطلب عند الحاجة إلى بيانات العقدة أولاً.

محاولة 4 (جديدة) - مثل المحاولة 2 ، ولكن تجاوز الكل الأعضاء الظاهريون الذين يتعين عليهم قراءة البيانات (CurrentNode, FindSiteMapNode, FindSiteMapNodeFromKey, GetChildNodes, GetCurrentNodeAndHintAncestorNodes, GetCurrentNodeAndHintNeighborhoodNodes, GetParentNode, GetParentNodeRelativeToCurrentNodeAndHintDownFromParent, GetParentNodeRelativeToNodeAndHintDownFromParent, HintAncestorNodes, HintNeighborhoodNodes) ، لمحاولة اعتراض قراءة العقدة الديناميكية في مكان ما.

هذا لم ينجح. لقد وضعت عبارات التصحيح في جميع الأعضاء المتجولين ، ويبدو أنه لا يتم استدعاء أي منهم على الإطلاق عند ربط البيانات بقائمة القائمة المنسدلة. التفسير الوحيد الذي يمكنني التفكير فيه هو أن العقد يتم قراءة جميعها في الذاكرة في واحدة أثناء BuildSiteMap اتصل ، بحيث SiteMapNode لا يضرب فئة المزود عند تعداد العقد الفرعية.

هل لدى أي شخص أي اقتراحات أفضل؟

هل كانت مفيدة؟

المحلول

فينا المخصصة ، نقوم بتجاوز طريقة BuildSitemAP ونقوم ببناء sitemapnodes يدويًا. لتغيير و/أو إضافة خصائص مخصصة ، نضيف سمات مخصصة إلى sitemapnodes عن طريق إنشاء nameValuEcollection وإضافة تمرير هذا إلى مُنشئ SitemapNode.

نصائح أخرى

أنت قريب جدًا من المحاولة رقم 2 - تحتاج أيضًا إلى تجاوز getParentNode و FindSitemApnode كذلك.

بفضل مارك وريكس على الاقتراحات. ما انتهى بي الأمر هو ترك موفر Sitemap بمفرده وإصلاح العقدة الواحدة في الصفحة الرئيسية ، وبالتالي:

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

ومع ذلك ، قبلت إجابة مارك ، لأن هذه هي الطريقة التي سأفعل بها إذا اتضح أن هناك حاجة إلى إجراء تعديلات أكثر شمولاً في المستقبل.

شكرا كريستيان على بحثك. باستخدام نتائجك ، توصلت إلى ما يلي قد يساعد الآخرين:

' 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
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top