Geoprocessing task

The Geoprocessing task allows you to perform geoprocessing in your Silverlight geographic information system (GIS) applications by executing geoprocessing models that you've created with ArcGIS. Geoprocessing models chain together GIS analysis operations so that they can be executed automatically. These models generally consist of a series of tools in ArcToolbox, chained together logically to accomplish a specific task. For example, a model might interpolate an elevation surface from a set of input spot heights, then create contours from that surface. Instead of manually opening two separate tools from ArcToolbox, you just run the model. If you need to perform this operation on 100 datasets, you can automate the model to run 100 times. This makes geoprocessing both powerful and convenient.

The Geoprocessor class in the ArcGIS API for Silverlight gives you access to geoprocessing models that have been published to ArcGIS Server as geoprocessing services. These services are useful because geoprocessing can be computationally intensive and requires GIS software to run the tools and models. It's often more efficient to send geoprocessing jobs to a centralized server rather than relying on the processing power of client machines to perform the analysis. It can also be impractical to implement geoprocessing logic in your application or to expect users to install additional software.

Before you can use the Geoprocessing task, you need to have the following information about the geoprocessing service you want to use:

  • The URL of the service
  • The required inputs and outputs of the task
  • Whether the task is asynchronous or synchronous

All of these items are described in the ArcGIS Services Directory, which is a browseable depiction of what's available on an ArcGIS Server. The URL for the Services Directory is http://<server name>/<instance name>/rest/services. See Discovering Services for general information about how to use the Services Directory.

A Services Directory page for a Geoprocessing task is shown in the following screen shot. When you navigate to this page, the URL to of the service will be displayed in the browser's address bar. The Execution Type shows whether the task is synchronous (esriExecutionTypeSynchronous) or asynchronous (esriExecutionTypeAsynchronous). For each parameter, you'll need to know the parameter's name, data type, and whether it's used for input or returned as output. This information is circled in the screen shot.

Note:

The Data Types shown match the classes you'll use when initializing parameters in your code. Input parameters have a direction of esriGPParameterDirectionInput, while output parameters have a direction of esriGPParameterDirectionOutput.

GP Services Directory

As with all tasks, you'll initialize, execute, and process the results of the Geoprocessing task in your Silverlightapplication's .NET code (that is, code-behind). The Geoprocessing task does not contain visual components, so you can't use XAML to interact with it. However, you'll typically define an interface for the task's input (for example, a Map control and a Draw object) and output (for example, a GraphicsLayer with MapTips) in XAML. For examples of implementing a task's input and output interfaces, see Query task, Find task, and Identify task. The remainder of this topic focuses on manipulating the task in .NET code. All the code is written in C#.

Initializing a Geoprocessing task

To initialize a Geoprocessing task, declare a Geoprocessor object, instantiate it with the new keyword, and pass the URL of the geoprocessing service's REST endpoint to the constructor as shown in the following code:

Geoprocessor geoprocessorTask = new Geoprocessor("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" + 
    "Specialty/ESRI_Currents_World/GPServer/MessageInABottle");

Specifying a Geoprocessing task's input parameters

The Geoprocessing task's execution methods take a list of GPParameter objects as input. All the geoprocessing parameter classes (for example, GPFeatureRecordSetLayer, GPDouble, GPRecordSet, GPRasterData, and so on.) derive from this class. The MessageInABottle service, shown in the Services Directory figure above, has two input parameters: Input_Point, which is of type GPFeatureRecordSetLayer, and Days, which is of type GPDouble. The code to initialize the parameters for this task is as follows:

List<GPParameter> parameters = new List<GPParameter>();
    parameters.Add(new GPFeatureRecordSetLayer("Input_Point", e.MapPoint));
    parameters.Add(new GPDouble("Days", Convert.ToDouble(DaysTextBox.Text)));

Using a synchronous geoprocessing service

There are two sets of members for executing and handling the results of a Geoprocessing task. Which members you use depends on whether the geoprocessing service executes synchronously or asynchronously. In ArcGIS Server, synchronous geoprocessing services return the results of each operation to the client as soon as the operation is complete—no results are stored on the server. Alternatively, asynchronous services store results on the server and return a job ID to the client. The client can then use this ID to retrieve the results at a convenient time. Synchronous services are intended for geoprocessing operations that take a short amount of time to execute (for example, less than three seconds), while asynchronous services should be used for longer-running operations.

When using a service that executes synchronously, initiate the operation using the ExecuteAsync method. To retrieve results, you can either specify a handler for the ExecuteCompleted event or use the ExecuteLastResult property. Use of ExecuteAsync and the ExecuteCompleted event for the MessageInABottle service is shown in the following code. The event handler loops through the results features, adding each to a GraphicsLayer. Each GPParameter in the results that are passed to the handler is assumed to be a GPFeatureRecordSetLayer object since this is the output type listed in the service's information page.

The code assumes that a Map control, with an x:Name of MyMap and containing a GraphicsLayer with an ID of MyGraphicsLayer, along with a Symbol with an x:Key of PathLineSymbol, have been created and are available to the handler.

geoprocessorTask.ExecuteCompleted += GeoprocessorTask_ExecuteCompleted;
geoprocessorTask.ExecuteAsync(parameters);
.
.
.
private void GeoprocessorTask_ExecuteCompleted(object sender, GPExecuteCompleteEventArgs e)
{
    GraphicsLayer graphicsLayer = MyMap.Layers["MyGraphicsLayer"] as GraphicsLayer;

    foreach (GPParameter gpParameter in e.Results.OutParameters)
    {
        GPFeatureRecordSetLayer gpLayer = gpParameter as GPFeatureRecordSetLayer;
        foreach (Graphic graphic in gpLayer.FeatureSet.Features)
        {
            graphic.Symbol = PathLineSymbol;
            graphicsLayer.Graphics.Add(graphic);
        }
    }
}

Using an asynchronous geoprocessing service

As previously explained, when a client initiates an operation on an asynchronous geoprocessing service, the service returns a job ID to the client, which can then be used to retrieve the operation's results. The results are not automatically returned to the client when the operation is completed, but rather are stored on the server and are sent to the client only when the client requests them. Accordingly, you initiate an operation on an asynchronous geoprocessing service by calling the Geoprocessing task's SubmitJobAsync method, rather than ExecuteAsync, as shown in the following code:

geoprocessingTask.SubmitJobAsync(parameters);

A job's results can only be retrieved after the operation has completed. Asynchronous geoprocessing services do not notify the client when a job is complete, so it's up to the client to check with the service to determine the status of the job. By default, the ArcGIS API for Silverlight does this for you automatically and fires the Geoprocessing task's JobCompleted event once an operation is done executing. A handler for JobCompleted is typically where you'll request an asynchronous operation's results. To get these results, the Geoprocessing task defines the following methods, each of which returns the results in a different format:

  • GetResultDataAsync—Retrieves a collection of objects that expose all the result data (for example, a collection of graphics containing geometry and attributes).
  • GetResultImageLayerAsync—Retrieves a GPResultImageLayer. This can be used to display the results by adding it directly to the map but does not contain information about individual results.
  • GetResultImageAsync—Retrieves a GPResultImage, which contains a MapImage with the geometry of the results.

Each method requires you to specify the operation's job ID and the name of the output parameter to retrieve. For each, the results are passed to an event of the form <operation name>Completed (for example, GetResultImageCompleted) and a property of the form <operation name>LastResult (for example, GetResultImageLastResult) as soon as they are returned to the client.

The following code demonstrates use of JobCompleted, GetResultDataAsync, and GetResultDataCompleted. The code for JobCompleted requests data for an output parameter called Clipped_Counties. In GetResultDataCompleted, the following is assumed:

  • There is a Map with an x:Name of MyMap.
  • The Map contains a GraphicsLayer with an ID of MyResultGraphicsLayer.
  • A symbol with an x:Key of DefaultFillSymbol has been created.
  • The output parameters are of type GPFeatureRecordSetLayer.

The GetResultDataCompleted handler shown in the following code iterates through the results features, adding each to a GraphicsLayer:

geoprocessingTask.JobCompleted += GeoprocessorTask_JobCompleted;
.
.
.
private void GeoprocessorTask_JobCompleted(object sender, JobInfoEventArgs e)
{
    Geoprocessor geoprocessorTask = sender as Geoprocessor;
    geoprocessorTask.GetResultDataCompleted += GeoprocessorTask_GetResultDataCompleted;
    geoprocessorTask.GetResultDataAsync(e.JobInfo.JobId, "Clipped_Counties");
}

private void GeoprocessorTask_GetResultDataCompleted(object sender, GPParameterEventArgs e)
{
    GraphicsLayer graphicsLayer = MyMap.Layers["MyResultGraphicsLayer"] as GraphicsLayer;

    GPFeatureRecordSetLayer gpLayer = e.Parameter as GPFeatureRecordSetLayer;
    foreach (Graphic graphic in gpLayer.FeatureSet.Features)
    {
        graphic.Symbol = DefaultFillSymbol;
        graphicsLayer.Graphics.Add(graphic);
    }
}

By default, a Geoprocessing task checks the job status of asynchronous operations every five seconds. To change this, set the UpdateDelay property. This property is specified in milliseconds. The following statement sets the interval to ten seconds:

geoprocessingTask.UpdateDelay = 10000;

If you don't want the Geoprocessing task to check the status of asynchronous operations automatically, you can use the CancelJobStatusUpdates method to disable the default behavior, then check the status with the CheckJobStatusAsync method. The StatusUpdated event is used to get the job ID and call CancelJobStatusUpdates and to handle the result of the call to CheckJobStatusAsync. This approach is shown in the following code:

// Wire status updated event and initiate the asynchronous GP operation.
geoprocessorTask.StatusUpdated += geoprocessorTask_StatusUpdated;
geoprocessorTask.SubmitJobAsync(parameters);
.
.
.
// Manually check the job's status. The result is passed to the StatusUpdated handler.
geoprocessorTask.CheckJobStatusAsync(jobID);

void geoprocessorTask_StatusUpdated(object sender, JobInfoEventArgs e)
{
    Geoprocessor geoprocessingTask = sender as Geoprocessor;
    switch (e.JobInfo.JobStatus)
    {
        case esriJobStatus.esriJobSubmitted:            
            // Disable automatic status checking.
            geoprocessingTask.CancelJobStatusUpdates(e.JobInfo.JobId);
            break;
        case esriJobStatus.esriJobSucceeded:
            // Get the results.
            geoprocessingTask.GetResultDataAsync(e.JobInfo.JobId, "<parameter name>");
            break;
        case esriJobStatus.esriJobFailed:
        case esriJobStatus.esriJobTimedOut:
            MessageBox.Show("operation failed");
            break;
        }
}