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