Common Custom tasks
Common_CustomTasks_VBNet\AsyncTask_VBNet\BasicAsyncTask.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 AsyncTask_VBNet
  ' Task specifying an architecture for submitting a job for asynchronous processing.  This architecture
  ' can be used for jobs that may take a long time to process.  Once operation input is submitted via
  ' the task's interface, the job is started and a response is returned to the client immediately, 
  ' allowing the user to submit additional jobs.  In progress jobs are indicated via a task result node.
  ' Job status checking is managed by JavaScript timeouts that issue callbacks to the server.
    <System.Web.UI.ToolboxData("<{0}:BasicAsyncTask runat=""server"" Width=""200px"" Transparency=""35"" " & ControlChars.CrLf & "        BackColor=""White"" TitleBarColor=""WhiteSmoke"" TitleBarSeparatorLine=""True"" " & ControlChars.CrLf & "        TitleBarHeight=""20px"" BorderColor=""LightSteelBlue"" BorderStyle=""Outset"" BorderWidth=""1px"" " & ControlChars.CrLf & "        Font-Names=""Verdana"" Font-Size=""8pt"" ForeColor=""Black""> </{0}:BasicAsyncTask>")> _
     Public Class BasicAsyncTask
        Inherits ESRI.ArcGIS.ADF.Web.UI.WebControls.FloatingPanelTask
        ' Creates the Execute button
        Protected Overrides Sub CreateChildControls()
            MyBase.CreateChildControls()

            ' Instantiate the Execute button, set its text, and add it to the task's cotnrols
            Dim executeButton As New System.Web.UI.HtmlControls.HtmlInputButton()
            executeButton.Value = "Execute"
            Controls.Add(executeButton)

            ' Create JavaScript that calls the Web ADF executeTask function.  We pass executeTask 
            ' the task's callback function string so the call is linked to the current task
            ' instance.
            Dim executeTaskJavaScript As String = String.Format("ESRI.ADF.Tasks.executeTask('',""{0}"");", Me.CallbackFunctionString)
            ' Wire the JavaScript to fire when the Execute button is clicked
            executeButton.Attributes.Add("onclick", executeTaskJavaScript)
        End Sub

#Region "FloatingPanelTask Overrides - ExecuteTask, GetGISResourceItemDependencies"

        ' Submits and checks the status of asynchronous jobs, then creates a task results node
        ' accordingly
        Public Overrides Sub ExecuteTask()
            Dim callbackArgsCollection As System.Collections.Specialized.NameValueCollection = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackUtility.ParseStringIntoNameValueCollection(Me.CallbackEventArgument)

            ' Retrieve the task and async job IDs from the callback arguments.  The task job ID is 
            ' created by the Task framework and is used to link the task to task results.  The 
            ' asynchronousJobID is created in this implementation and is used to check the status
            ' of the job submitted for asynchronous processing.
            Dim taskFrameworkJobID As String = callbackArgsCollection("taskJobID")
            Dim asynchronousJobID As String = callbackArgsCollection("asyncJobID")

            ' Initialize the task results
            Me.Results = Nothing

            ' If an async job ID was not included in the callback arguments, then the callback was
            ' generated by the initial click of the Execute button.  The job therefore needs to be
            ' submitted for asynchronous processing.
            If String.IsNullOrEmpty(asynchronousJobID) Then
                ' Call method to submit the job and get the job's ID
                asynchronousJobID = SubmitSimJob()
                ' Uncomment to test against the BufferPoints tool of the BufferTools Geoprocessing service
                'asynchronousJobID = SubmitBufferPointsJob();

                asynchronousJobID = asynchronousJobID.Trim()
                ' Add the job ID to the list of in-progress jobs
                Me.JobsInProgress.Add(asynchronousJobID)
            End If

            ' Get the job's status
            Dim jobStatus As ESRI.ArcGIS.ADF.Web.DataSources.JobStatus
            jobStatus = GetSimJobStatus(asynchronousJobID)
            ' Uncomment to test against the BufferPoints tool of the BufferTools Geoprocessing service
            'jobStatus = GPFunctionality.GetJobStatus(asynchronousJobID);

            ' Construct a task result node to show the status
            Dim taskResultNode As New ESRI.ArcGIS.ADF.Web.UI.WebControls.TaskResultNode()
            ' Pass the node instance and the task job ID to the node setup method
            TaskResults.SetupTaskResultNode(Me, taskFrameworkJobID, Nothing, taskResultNode)

            ' Give the node an indentation
            taskResultNode.TextCellStyleAttributes.Add("padding-left", "5px")
            ' Set up the node to do nothing when clicked
            taskResultNode.ClickBehavior = ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNodeClickBehavior.None

            ' Convert the job status to a string
            Dim jobStatusString As String = jobStatus.ToString()

            ' Check the status and take action accordingly
            Select Case jobStatus
                ' Job succeeded
                Case ESRI.ArcGIS.ADF.Web.DataSources.JobStatus.Succeeded
                    ' Get the messages for the completed job
                    Dim jobResultMessages As String = GetSimJobResult(asynchronousJobID)
                    ' Uncomment to test against the BufferPoints tool of the BufferTools Geoprocessing service
                    'string jobResultMessages = GetBufferPointsResult(asynchronousJobID);

                    ' Set the text of the task result node to include the task's title, the job 
                    ' status, and the job messages
                    taskResultNode.Text = String.Format("{0} {1} <BR> {2}", Me.Title, jobStatusString, jobResultMessages)

                    ' Remove the job from the in-progress list
                    Me.JobsInProgress.Remove(asynchronousJobID)


                    ' Job is still in progress
                Case Else
                    ' Set the task result node's text to include the task's title and job status
                    taskResultNode.Text = String.Format("{0} {1}", Me.Title, jobStatusString)
                    ' Set the task result node's image to be the Web ADF's callback activity indicator
                    taskResultNode.LegendCollapsedImage = "/aspnet_client/ESRI/WebADF/images/callbackActivityIndicator.gif"
                    taskResultNode.LegendExpandedImage = "/aspnet_client/ESRI/WebADF/images/callbackActivityIndicator.gif"

                    ' Construct JavaScript to set a timeout that calls the Web ADF startJob function.  
                    ' This function issues a callback with the specified arguments and task ID.  In 
                    ' this implementation, this callback is handled to check the async job's status
                    Dim checkStatusJavaScript As String = String.Format("window.setTimeout(" & """ESRI.ADF.Tasks.startJob('asyncJobID={0}',\""{1}\"",{2})"", 2000);", asynchronousJobID, Me.CallbackFunctionString, taskFrameworkJobID)

                    ' Package the JavaScript as a CallbackResult and add it to the task's collection
                    Dim checkStatusCallbackResult As ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(checkStatusJavaScript)
                    Me.CallbackResults.Add(checkStatusCallbackResult)

            End Select

            ' Return the job status task result node as the task's results
            Results = taskResultNode
        End Sub

        ' The task has no resource dependencies, so this method is overriden to return an empty list
        Public Overrides Function GetGISResourceItemDependencies() As System.Collections.Generic.List(Of ESRI.ArcGIS.ADF.Web.UI.WebControls.GISResourceItemDependency)
            Return New System.Collections.Generic.List(Of ESRI.ArcGIS.ADF.Web.UI.WebControls.GISResourceItemDependency)()
        End Function

#End Region

#Region "Instance Methods"

        ' Submits a new job and returns the job's ID
        Private Function SubmitSimJob() As String
            ' Return a new GUID
            Return System.Guid.NewGuid().ToString()
        End Function

        ' Retrieves the status of the job with the specified ID
        Private Function GetSimJobStatus(ByVal JobID As String) As ESRI.ArcGIS.ADF.Web.DataSources.JobStatus
            ' Generate a random number between 0 and 3
            Dim randomizer As New System.Random()
            Dim randomInteger As Integer = randomizer.Next(0, 4)

            ' If the random number is 0, return a successful result.  Otherwise, return a result
            ' indicating the job is still in progress.
            If randomInteger = 0 Then
                Return ESRI.ArcGIS.ADF.Web.DataSources.JobStatus.Succeeded
            Else
                Return ESRI.ArcGIS.ADF.Web.DataSources.JobStatus.Submitted
            End If
        End Function

        ' Retrieves the result of the job having the passed-in ID
        Private Function GetSimJobResult(ByVal JobID As String) As String
            ' Return a string with the Job ID and time
            Return String.Format("JobID: {0} <br />Time Returned: {1}", JobID, System.DateTime.Now.ToLongTimeString())
        End Function

#End Region

#Region "Instance Properties"

        ' Returns a list containing the IDs of submitted jobs
        Private ReadOnly Property JobsInProgress() As System.Collections.Generic.List(Of String)
            Get
                ' Try retrieving the jobs list from state
                'INSTANT VB NOTE: The local variable jobsInProgress was renamed since Visual Basic will not allow local variables with the same name as their enclosing function or property:
                Dim jobsInProgress_Renamed As System.Collections.Generic.List(Of String) = TryCast(StateManager.GetProperty("JobsInProgress"), System.Collections.Generic.List(Of String))

                ' If the list was not found, instantiate a new list and store it in state
                If jobsInProgress_Renamed Is Nothing Then
                    jobsInProgress_Renamed = New System.Collections.Generic.List(Of String)()
                    StateManager.SetProperty("JobsInProgress", jobsInProgress_Renamed)
                End If

                Return jobsInProgress_Renamed
            End Get
        End Property

        ' Retrieves the task's first buddied TaskResults control
        Private ReadOnly Property TaskResults() As ESRI.ArcGIS.ADF.Web.UI.WebControls.TaskResults
            Get
                'INSTANT VB NOTE: The local variable taskResults was renamed since Visual Basic will not allow local variables with the same name as their enclosing function or property:
                Dim taskResults_Renamed As ESRI.ArcGIS.ADF.Web.UI.WebControls.TaskResults = Nothing
                If TaskResultsContainers(0) IsNot Nothing Then
                    taskResults_Renamed = TryCast(ESRI.ArcGIS.ADF.Web.UI.WebControls.Utility.FindControl(TaskResultsContainers(0).Name, Page), ESRI.ArcGIS.ADF.Web.UI.WebControls.TaskResults)
                End If

                Return taskResults_Renamed
            End Get
        End Property

#End Region

#Region "Members for Testing Against the BufferTools Geoprocessing Service"

        Private _geoprocessingFunctionality As ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.GeoprocessingFunctionality = Nothing

        ' Submits a new BufferPoints geoprocessing operation
        Private Function SubmitBufferPointsJob() As String
            ' Retrieve an array containing information about BufferPoints' parameters
            Dim gpTaskName As String = "BufferPoints"
            Dim gpToolInfo As ESRI.ArcGIS.ADF.Web.DataSources.GPToolInfo = GPFunctionality.GetTask(gpTaskName)
            Dim gpParameterInfoArray() As ESRI.ArcGIS.ADF.Web.DataSources.GPParameterInfo = gpToolInfo.ParameterInfo

            ' Get a reference to the operation's input graphics layer from the parameter array
            Dim inputGpFeatureGraphicsLayer As ESRI.ArcGIS.ADF.Web.DataSources.GPFeatureGraphicsLayer = CType(gpParameterInfoArray(0).Value, ESRI.ArcGIS.ADF.Web.DataSources.GPFeatureGraphicsLayer)
            Dim inputFeatureGraphicsLayer As ESRI.ArcGIS.ADF.Web.Display.Graphics.FeatureGraphicsLayer = inputGpFeatureGraphicsLayer.Layer

            ' Create a point and add it to the input graphics layer
            Dim adfPoint As New ESRI.ArcGIS.ADF.Web.Geometry.Point(730324, 2309070)
            inputFeatureGraphicsLayer.Add(adfPoint)

            ' Initialize the input linear unit (distance) to be 300 miles
            Dim gpLinearUnit As New ESRI.ArcGIS.ADF.Web.DataSources.GPLinearUnit()
            gpLinearUnit.Units = ESRI.ArcGIS.ADF.Web.DataSources.Units.Miles
            gpLinearUnit.Value = 300

            ' Package the input parameters in an array and submit the job
            Dim gpValueArray(1) As ESRI.ArcGIS.ADF.Web.DataSources.GPValue
            gpValueArray(0) = inputGpFeatureGraphicsLayer
            gpValueArray(1) = gpLinearUnit
            Dim jobID As String = GPFunctionality.SubmitJob(gpTaskName, gpValueArray)

            ' Return the submitted job's ID
            Return jobID
        End Function

        ' Retrieves the result of the BufferPoints job having the passed-in ID
        Private Function GetBufferPointsResult(ByVal jobID As String) As String
            ' Get the geoprocessing result of the BufferPoints job with the passed-in ID
            Dim gpResult As ESRI.ArcGIS.ADF.Web.DataSources.GPResult = GPFunctionality.GetJobResult("BufferPoints", jobID, Nothing, False)
            Dim resultsGpValuesArray() As ESRI.ArcGIS.ADF.Web.DataSources.GPValue = gpResult.Values

            ' Get the graphics layer containing the result.  Note that nothing is done with this graphics 
            ' layer here; the code to retrieve the result is included to for instructive purposes.
            Dim resultsGpFeatureGraphicsLayer As ESRI.ArcGIS.ADF.Web.DataSources.GPFeatureGraphicsLayer = TryCast(resultsGpValuesArray(0), ESRI.ArcGIS.ADF.Web.DataSources.GPFeatureGraphicsLayer)
            Dim resultsFeatureGraphicsLayer As ESRI.ArcGIS.ADF.Web.Display.Graphics.FeatureGraphicsLayer = resultsGpFeatureGraphicsLayer.Layer

            ' Return the result messages or an empty string if there are no messages
            If gpResult.Messages IsNot Nothing Then
                Return gpResult.Messages(gpResult.Messages.Length - 1).MessageDesc
            Else
                Return ""
            End If
        End Function

        ' Gets the geoprocessing functionailty for the first geoprocessing resource referenced by the 
        ' GeoprocessingResourceManager having an ID of "GeoprocessingResourceManager1"
        Private ReadOnly Property GPFunctionality() As ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.GeoprocessingFunctionality
            Get
                ' Check whether the GP functionality member variable has already been initialized
                If _geoprocessingFunctionality Is Nothing Then
                    ' Get the geoprocessing resource manager
                    Dim geoprocessingResourceManager As ESRI.ArcGIS.ADF.Web.UI.WebControls.GeoprocessingResourceManager = TryCast(Page.FindControl("GeoprocessingResourceManager1"), ESRI.ArcGIS.ADF.Web.UI.WebControls.GeoprocessingResourceManager)

                    ' Get the first resource from the resource manager
                    Dim geoprocessingResource As ESRI.ArcGIS.ADF.Web.DataSources.IGeoprocessingResource = geoprocessingResourceManager.GetResource(0)

                    ' Create a geoprocessing functionality from the resource and assign it to the GP functionality member
                    ' variable
                    _geoprocessingFunctionality = CType(geoprocessingResource.CreateFunctionality(GetType(ESRI.ArcGIS.ADF.Web.DataSources.IGeoprocessingFunctionality), Nothing), ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.GeoprocessingFunctionality)

                    ' Make sure the GP functionality is initialized
                    If (Not _geoprocessingFunctionality.Initialized) Then
                        _geoprocessingFunctionality.Initialize()
                    End If

                End If
                Return _geoprocessingFunctionality
            End Get
        End Property

#End Region
    End Class
End Namespace