Common Security
Common_Security_VBNet\App_Code\GetMapInformation.vb
' Copyright 2010 ESRI
' 
' All rights reserved under the copyright laws of the United States
' and applicable international laws, treaties, and conventions.
' 
' You may freely redistribute and use this sample code, with or
' without modification, provided you include the original copyright
' notice and use restrictions.
' 
' See the use restrictions.
' 


Imports Microsoft.VisualBasic
Imports System
Namespace CustomComponents
  Public Class GetMapInformation
        Implements ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IMapServerCommandAction
    #Region "IServerAction Members"

    ' Executes the action for the command. Gets information about the map's layers, packages that 
    ' information as a callback result, and passes the callback result back to the client for display.
    Private Sub ServerAction(ByVal toolbarItemInfo As ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.ToolbarItemInfo) Implements ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IServerAction.ServerAction
      ' Get a reference to the map control to which the toolbar is buddied
      Dim adfMap As ESRI.ArcGIS.ADF.Web.UI.WebControls.Map = CType(toolbarItemInfo.BuddyControls(0), ESRI.ArcGIS.ADF.Web.UI.WebControls.Map)

      Try
        ' Get map/layer/field information via private method
        Dim mapInfoHtml As String = GetMapAndLayerInformation(adfMap)

        ' Create a callback result that will replace the content of a div tag in the page with the 
        ' map information.  The "HtmlGenericControl" paramter indicates the type of control to be
        ' updated.  The "divMapInfo" parameter indicates the ID of the control to be updated; 
        ' divMapInfo is a <div> element on the Default.aspx page.  The "innercontent" parameter
        ' specifies that the HTML content of the specified control is to be updated.  The mapInfoHtml
        ' parameter specifies the content with which we wish to update the specified control.
        Dim callbackResult As ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateSetInnerContent("divMapInfo", mapInfoHtml)

        ' add the callback result to the map's results so they will get
        '  passed to the page
        adfMap.CallbackResults.Add(callbackResult)
      Catch exception As System.Exception
        Dim errorCallbackResult As ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult = Utility.GetErrorCallback(exception)
        adfMap.CallbackResults.Add(errorCallbackResult)
      End Try
    End Sub

    #End Region

    #Region "Instance Methods"

    ' Retrieves information about map services, layers, and fields for vector layers, and returns 
    ' this information as an HTML-formatted string.
    Private Function GetMapAndLayerInformation(ByVal adfMap As ESRI.ArcGIS.ADF.Web.UI.WebControls.Map) As String
      ' make sure map resources are initialized
      If (Not adfMap.InitializedFunctionalities) Then
        adfMap.InitializeFunctionalities()
      End If

      ' Intantiate a string builder object to use in creating the HTML markup.  Initialize the string builder
      ' with a title for the map information.
      Dim mapInfoStringBuilder As System.Text.StringBuilder = New System.Text.StringBuilder("<h2>Map Information:</h2>")

      Dim fieldNames, layerIDs, layerNames As String()

      ' loop through each map service
      For Each commonMapFunctionality As ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality In adfMap.GetFunctionalities()
        ' Add the resource definition and name to the map information HTML
        Dim gisResource As ESRI.ArcGIS.ADF.Web.DataSources.IGISResource = commonMapFunctionality.Resource
        mapInfoStringBuilder.AppendFormat("<h3>Service: {0} ({1})</h3>", gisResource.ResourceDefinition, gisResource.Name)

        ' Check whether the current resource supports ADF QueryFunctionality.  We need this to access the 
        ' fields of vector layers
        If gisResource.SupportsFunctionality(GetType(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality)) Then
          Dim commonQueryFunctionality As ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality = CType(gisResource.CreateFunctionality(GetType(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality), Nothing), ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality)

          ' Get layer IDs and names
          commonQueryFunctionality.GetQueryableLayers(Nothing, layerIDs, layerNames)

          ' Iterate through the layer IDs
          Dim i As Integer = 0
          Do While i < layerIDs.Length
            ' Add the current layer's name to the map information HTML
            mapInfoStringBuilder.AppendFormat("<h4>Layer {0}</h4>Fields:<br/>", layerNames(i))

            ' Retrieve and iterate through the field names of the current layer
            fieldNames = commonQueryFunctionality.GetFields(Nothing, layerIDs(i))
            For Each fieldName As String In fieldNames
              ' Add the name of the current field to the map information HTML
              mapInfoStringBuilder.AppendFormat("{0}<br/>", fieldName)
            Next fieldName
            mapInfoStringBuilder.Append("<br>")
            i += 1
          Loop
        End If
        mapInfoStringBuilder.Append("<br>")
      Next commonMapFunctionality
      Return mapInfoStringBuilder.ToString()
    End Function

    #End Region
  End Class

  Public Class Utility
    ' Constructs a callback result that will display an error message based on the passed-in
    ' exception
    Public Shared Function GetErrorCallback(ByVal exception As System.Exception) As ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult
      ' Create a callback result to display an error message
      Dim jsAlertErrorMessage As String = GetJavaScriptErrorString(exception)
      Dim alertCallbackResult As ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(jsAlertErrorMessage)
      Return alertCallbackResult
    End Function

    ' Constructs JavaScript necessary to display an error message based on the passed-in exception.
    Public Shared Function GetJavaScriptErrorString(ByVal exception As System.Exception) As String
      ' Get the website's configuration file
      Dim webConfig As System.Configuration.Configuration = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(System.Web.HttpContext.Current.Request.ApplicationPath)

      ' Get the "compilation" section of the config file
      Dim compilationSection As System.Web.Configuration.CompilationSection = TryCast(webConfig.GetSection("system.web/compilation"), System.Web.Configuration.CompilationSection)

      ' If the config file's compilation section specifies debug mode, include 
      ' stack trace information in the error message.  Otherwise, just return 
      ' the exception message.
      Dim errorMessage As String = Nothing
      If (Not compilationSection Is Nothing) AndAlso (compilationSection.Debug) Then
        Dim stackTrace As String = exception.StackTrace.Replace("\", "\\")
        stackTrace = stackTrace.Replace(Constants.vbLf, "\n")
        stackTrace = stackTrace.Replace(Constants.vbCr, "\r")
        errorMessage = exception.Message & "\n\n" & stackTrace.Trim()
      Else
        errorMessage = exception.Message
      End If

      ' Create a callback result to display an error message
      Dim jsAlertException As String = "alert('" & errorMessage & "')"
      Return jsAlertException
    End Function

    ' Gets the ID of the layer matching the input layer name.
    Public Shared Function GetLayerID(ByVal layerName As String, ByVal mapFunctionality As ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality) As String
      Dim layerID As String = String.Empty

      ' get layerIDs and names from the passed-in map functionality
      Dim layerIDs, layerNames As String()
      mapFunctionality.GetLayers(layerIDs, layerNames)

      ' Loop through the layer names.  If one of the names matches the passed-in layer name,
      ' get that layer's ID and exit the loop.
      Dim i As Integer = 0
      Do While i < layerIDs.Length
        If layerNames(i) = layerName Then
          layerID = layerIDs(i)
          Exit Do
        End If
        i += 1
      Loop
      Return layerID
    End Function

    ' Finds the node having the passed-in name from among the input node or its child nodes. 
    ' Useful for searching a Toc with group layers.
    Public Shared Function FindNodeRecursive(ByVal treeViewPlusNode As ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode, ByVal nodeName As String) As ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode
      ' Check whether the text of the passed-in node matches the text sought.  Return the node if so.
      If treeViewPlusNode.Text = nodeName Then
        Return treeViewPlusNode
      End If

      ' Iterate through the passed-in node's child nodes, calling this function on each.
      For Each childTreeViewPlusNode As ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode In treeViewPlusNode.Nodes
        Dim childNode As ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode = FindNodeRecursive(childTreeViewPlusNode, nodeName)
        If Not childNode Is Nothing Then
          Return childNode
        End If
      Next childTreeViewPlusNode

      ' If the code reaches this point, no match was found. 
      Return Nothing
    End Function

    ' Retrieves the first control of the passed-in type from the passed-in control collection
    Public Shared Function FindControlOfType(ByVal type As System.Type, ByVal controlCollection As System.Web.UI.ControlCollection) As System.Web.UI.Control
      ' Iterate through all the controls in the passed-in control collection
      For Each webControl As System.Web.UI.Control In controlCollection
        ' If the current control is of the passed-in type, return it.
        If type.IsInstanceOfType(webControl) Then
          Return webControl
        ElseIf webControl.HasControls() Then
          ' The current control has child controls, so call this function on those child controls
          Dim childWebControl As System.Web.UI.Control = FindControlOfType(type, webControl.Controls)
          If Not childWebControl Is Nothing Then
            Return childWebControl
          End If
        End If
      Next webControl

      ' If the code reaches this point, no match was found. 
      Return Nothing
    End Function

    ' Finds a control by checking whether the passed-in control or any child controls have an ID matching the 
    ' passed-in control ID
    Public Shared Function FindControlRecursive(ByVal webControl As System.Web.UI.Control, ByVal controlID As String) As System.Web.UI.Control
      ' If the passed-in control has an ID that matches the passed-in ID, return it
      If webControl.ID = controlID Then
        Return webControl
      End If

      ' Iterate through the child control's of the current control, calling this function on each
      For Each childWebControl As System.Web.UI.Control In webControl.Controls
        Dim matchingControl As System.Web.UI.Control = FindControlRecursive(childWebControl, controlID)
        If Not matchingControl Is Nothing Then
          Return matchingControl
        End If
      Next childWebControl

      ' If the code reaches this point, no match was found. 
      Return Nothing
    End Function
  End Class
End Namespace