Visual Basic (Declaration) | |
---|---|
Public Overloads Sub ExecuteAsync( _ ByVal printParameters As PrintParameters, _ ByVal userToken As Object _ ) |
C# | |
---|---|
public void ExecuteAsync( PrintParameters printParameters, object userToken ) |
Synchronous -vs- Asynchronous Geoprocessing Tasks
When it comes to using the PrintTask in web development using the ArcGIS Runtime SDK for WPF to generate an image on ArcGIS Server, as a developer you have two options: synchronous geoprocessing tasks and asynchronous geoprocessing tasks. In a traditional sense the terms "synchronous" means that your computer will wait while a process executes on the server and "asynchronous" means that your computer does not have to wait for the process to finish execution and you can move on to other operations. However in web development using WPF, all web requests are asynchronous in nature, meaning that once a web request has initiated you are free to perform other operations/functionality in your application as it remains highly responsive. When it comes to the PrintTask there are some important differences between the synchronous geoprocessing tasks and asynchronous geoprocessing tasks that are outlined as follows:
- A synchronous geoprocessing task means that once ArcGIS Server starts the task to generate the image, ArcGIS Server is dedicated to that operation until it completes. It should be noted that from the web based WPF application’s perspective, that once the synchronous geoprocessing task has been initiated you are still free to perform other operations as the application remains highly responsive. See the code example in this document for how a synchronous geoprocessing task works.
- An asynchronous geoprocessing task means that ArcGIS Server will control when it can handle generating an image based upon its computing load and will multi-task multiple operations simultaneously until the operation is complete. Again it should be noted that from the web based WPF application’s perspective, that once the asynchronous geoprocessing task has been initiated you are still free to perform other operations as the application remains highly responsive. See the code example in the PrintTask.SubmitJobAsync Method Method for how an asynchronous geoprocessing task works.
When constructing a PrintTask the following Types are used by both the synchronous geoprocessing tasks or asynchronous geoprocessing tasks:
- PrintTask Constructor
- DisableClientCaching Property
- ProxyURL Property
- Token Property
- Url Property
The following table illustrates which PrintTask Types are dedicated exclusively to a synchronous geoprocessing task or an asynchronous geoprocessing task:
Synchronous geoprocessing task | Asynchronous geoprocessing task |
---|---|
CancelAsync Method | CancelJobAsync Method |
ExecuteAsync Method | CancelJobStatusUpdates Method |
GetServiceInfoAsync Method | SubmitJobAsync Method |
IsBusy Property | UpdateDelay Property |
ExecuteCompleted Event | StatusUpdated Event |
GetServiceInfoCompletedEvent | JobCompleted Event |
As a developer of a web based WPF application, when choosing whether to perform a PrintTask based upon the methodology of synchronous geoprocessing task or an asynchronous geoprocessing task, the following information may be helpful in the decision making process:
-
By default, a synchronous geoprocessing task is created when ArcGIS Server is installed and initially configured. This means that no other work is required on ArcGIS Server to enable using the PrintTask (other than starting the PrintingTools, Geoprocessing Service) by an ArcGIS WPF application developer. Typically in ArcGIS Server, this synchronous geoprocessing task is located under in the ArcGIS REST Services Directory in the Utilities folder as an Utilties/ExportWebMap (GPServer) Service. The Task is usually called Export Web Map Task and has an Execution Type of esriExecutionTypeSynchronous. For example, assume for the sample ESRI ArcGIS Server (http://servicesbeta2.esri.com/arcgis/rest/) the PrintTask.Url for the synchronous geoprocessing task would be as follows (see the following screen shot):
-
For small PrintTask operations using a synchronous geoprocessing task will probably yield faster results in generating a return image/pdf.
-
A web based WPF application can only issue one PrintTask via a synchronous geoprocessing task at a time. This means that it is not possible to have multiple PrintTask operations (i.e. generating multiple image/.pdf files at a time) using a synchronous geoprocessing task. Use the PrintTask.IsBusy Property to determine if an existing synchronous geoprocessing task is running before issuing the PrintTask.ExecuteAsync Method to avoid the Visual Studio runtime error: NotSupportedException was unhandled by user code ("Task does not support concurrent I/O operations. Cancel the pending request or wait for it to complete").
-
If multiple simultaneous PrintTask operations are necessary from a single web based WPF application (i.e. an application that produces numerous images/.pdf for cartographic production), then use the asynchronous geoprocessing task options for better performance.
-
If the PrintTask operations will be used for very large image/.pdf generation or numerous ArcGIS WPF applications will be utilizing a single ArcGIS Server and thereby causing internet browser time-out error messages, then an asynchronous geoprocessing task may be the better choice. It may be possible to increase the amount of time an internet browser waits before a time-out error message occurs when using a synchronous geoprocessing task but this will require testing to determine which option is best for your organization.
-
Using an asynchronous geoprocessing task requires configuring an ArcGIS Server Geoprocessing Task. This is not done automatically as part of the ArcGIS Server installation/configuration. One option is to use ArcMap to run the ArcToolbox: Server Tools | Printing | Export Web Map tool and when the Results are completed right click on the ExportWebMap session and Share As a Geoprocessing Service that can be used by ArcGIS Server. Another option is to use the default ArcGIS Server: Printing Tools, Geoprocessing Service (located in the Utilities folder) that is created when ArcGIS Server is initially installed/configured and change its Execution Mode from Synchronous to Asynchronous (see the following screen shot for an example test ArcGIS Server running on the local developement computer) and re-starting the service:
This will result in an ArcGIS REST Services Directory page that looks similar to the following screen shot:
-
Using the PrintTask via asynchronous geoprocessing task Types provide much better options to track the status of image/.pdf creation. The PrintTask.StatusUpdated Event uses the ESRI.ArcGIS.Client.Tasks.JobInfoEventArgs Class to give instant status information of the operation.
Parameters
- printParameters
- The print parameters.
- userToken
- The user token.
How to use:
When the application loads, enter a correct Url to an ArcGIS Server PrintTask based on a 'synchronous geoprocessing task'. Then click the 'ExecuteAsync' button to generate a .JPG image returned in an internet browser. Status informatonal messages will display to provide information on the PrintTask operation. Experiment by clicking the 'ExecuteAsync' button in rapid succession (ie. before the PrintTask has a chance to complete generating an image/.pdf file to better understand how a 'synchronous geoprocesing task' works.
The XAML code in this example is used in conjunction with the code-behind (C# or VB.NET) to demonstrate the functionality.
The following screen shot corresponds to the code example in this page.
XAML | Copy Code |
---|---|
<Grid x:Name="LayoutRoot" Background="White"> <esri:Map Background="White" HorizontalAlignment="Left" Margin="12,261,0,0" Name="MyMap" VerticalAlignment="Top" WrapAround="True" Height="300" Width="600" Extent="-10929488.234,4525208.388,-10906776.553,4535252.104"> <esri:Map.Layers> <esri:LayerCollection> <!-- Add some layers to the Map Control. --> <esri:ArcGISTiledMapServiceLayer Url="http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer" /> <esri:FeatureLayer Mode="OnDemand" DisableClientCaching="True" Url="http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Petroleum/KSWells/MapServer/0" /> </esri:LayerCollection> </esri:Map.Layers> </esri:Map> <!-- Url --> <sdk:Label Height="20" HorizontalAlignment="Left" Margin="8,100,0,0" Name="Label_Url" VerticalAlignment="Top" Width="31" Content="Url:"/> <TextBox Height="23" HorizontalAlignment="Left" Margin="8,118,0,0" Name="TextBox_Url" VerticalAlignment="Top" Width="605" FontSize="10" /> <!-- Buttons to perform the work. --> <Button Content="ExecuteAsync" Height="39" Width="201" HorizontalAlignment="Left" Margin="12,147,0,0" Name="Button_ExecuteAsync" VerticalAlignment="Top" Click="Button_ExecuteAsync_Click" IsEnabled="True"/> <Button Content="CancelAsync" Height="35" Width="201" HorizontalAlignment="Left" Margin="12,192,0,0" Name="Button_CancelAsync" VerticalAlignment="Top" Click="Button_CancelAsync_Click" IsEnabled="False"/> <!-- Provide PrintTask information messages. --> <sdk:Label Height="19" HorizontalAlignment="Left" Margin="229,147,0,0" Name="Label_StatusInfo" VerticalAlignment="Top" Width="120" Content="Status Information:"/> <ListBox Height="64" HorizontalAlignment="Left" Margin="229,163,0,0" Name="ListBox_StatusInformation" VerticalAlignment="Top" Width="383" /> <!-- Provide the instructions on how to use the sample code. --> <TextBlock Height="94" HorizontalAlignment="Left" Name="TextBlock1" VerticalAlignment="Top" Width="625" TextWrapping="Wrap" Text="When the application loads, enter a correct Url to an ArcGIS Server PrintTask based on a 'synchronous geoprocessing task'. Then click the 'ExecuteAsync' button to generate a .JPG image returned in an internet browser. Status informatonal messages will display to provide information on the PrintTask operation. Experiment by clicking the 'ExecuteAsync' button in rapid succession (ie. before the PrintTask has a chance to complete generating an image/.pdf file to better understand how a 'synchronous geoprocesing task' works." /> </Grid> |
C# | Copy Code |
---|---|
// Create a Global (aka. Member) variable for the PrintTask object that will be used in other // parts of the application. private ESRI.ArcGIS.Client.Printing.PrintTask _PrintTask; public MainPage() { InitializeComponent(); // Provide a valid PrintTask.Url for a "synchronous geoprocessing task" TextBox_Url.Text = "http://localhost:6080/arcgis/rest/services/Utilities/PrintingTools/GPServer/Export20Web20Map%20Task"; // Set the _PrintTask variable to a new instance of the PrintTask Class. _PrintTask = new ESRI.ArcGIS.Client.Printing.PrintTask(); // Prevent the internet browser from using a cache for the PrintTask operations. _PrintTask.DisableClientCaching = true; // Set the PrintTask.Url from what is entered in the TextBox. _PrintTask.Url = TextBox_Url.Text; // Wire up an Event Handler for the PrintTask.ExecuteCompleted Event. _PrintTask.ExecuteCompleted += printTask_ExecuteCompleted; } private void Button_ExecuteAsync_Click(object sender, System.Windows.RoutedEventArgs e) { // Define the settings for rendering the image/.pdf on the ArcGIS Server. // Define the ExportOptions. ESRI.ArcGIS.Client.Printing.ExportOptions myExportOptions = new ESRI.ArcGIS.Client.Printing.ExportOptions(); myExportOptions.Dpi = 96; //96 DPI is typical Window OS setting. myExportOptions.OutputSize = new Size(MyMap.ActualWidth, MyMap.ActualHeight); // Use the dimensions of the Map // Define the PrintParameters. ESRI.ArcGIS.Client.Printing.PrintParameters myPrintParameters = new ESRI.ArcGIS.Client.Printing.PrintParameters(MyMap); myPrintParameters.ExportOptions = myExportOptions; // Use the ExportOptions defined earlier. myPrintParameters.LayoutTemplate = "MAP_ONLY"; // Look to the REST service to see what layout templates are supported. myPrintParameters.Format = "JPG"; // Look to the REST service to see what image formats are supported. // NOTE: // If you try to submit more that one 'synchronous geoprocessing task' via PrintTask.ExecuteAsync at a time // using the ExecuteAsync methadology you will get a Visual Studio (Runtime) error: // NotSupportedException was unhandled by user code. "Task does not support concurrent I/O operations. Cancel // the pending request or wait for it to complete." // In order to overcome this, use the PrintTask.IsBusy Property and take action accordingly. if (_PrintTask.IsBusy == true) { // There is an existing 'synchronous geoprocessing task' PrintTask running. // Use a simple MessageBox to get user direction on whether to stay with the currently running 'synchronous // geoprocessing task' PrintTask or cancel it and start another one. System.Windows.MessageBoxResult myMessage = MessageBox.Show("Click 'Cancel' to kill the prior print job and print this one OR click 'OK' to finish the prior " + "print job and wait to re-click the Print button.", "Action Required", MessageBoxButton.OKCancel); if (myMessage == MessageBoxResult.Cancel) { // The user has opted to cancel the currently runnning 'synchronous geoprocessing task' PrintTask. // Kill the PrintTask. _PrintTask.CancelAsync(); // Clear out the status informational messages. ListBox_StatusInformation.Items.Clear(); // Create a UserToken to identify which PrintTask is running. string myToken = "MY TOKEN2"; // Use the 'synchronous geoprocessing task' PrintTask.ExecuteAsync Method. _PrintTask.ExecuteAsync(myPrintParameters, myToken); // Update the status informational messages. ListBox_StatusInformation.Items.Add("The PrintTask was started."); } else if (myMessage == MessageBoxResult.OK) { // The user has opted to let the currently runnning 'synchronous geoprocessing task' PrintTask complete. // Update the status informational messages. ListBox_StatusInformation.Items.Add("The PrintTask is busy (still processing)."); } } else if (_PrintTask.IsBusy == false) { // There is not and existing 'synchronous geoprocessing task' PrintTask running. // Clear out the status informational messages. ListBox_StatusInformation.Items.Clear(); // Create a UserToken to identify which PrintTask is running. string myToken = "MY TOKEN"; // Use the 'synchronous geoprocessing task' PrintTask.ExecuteAsync Method. _PrintTask.ExecuteAsync(myPrintParameters, myToken); // Enable button for the user to cancel the PrintTask request. Button_CancelAsync.IsEnabled = true; // Update the status informational messages. ListBox_StatusInformation.Items.Add("The PrintTask was started."); } } private void printTask_ExecuteCompleted(object sender, ESRI.ArcGIS.Client.Printing.PrintEventArgs e) { // Use only for ExecuteAsync operations (i.e. synchronous geoprocessing tasks). // Get any error information (add your own enhancements if desired). System.Exception mySystemException = e.Error; // Get the PrintResult from the completed operation. ESRI.ArcGIS.Client.Printing.PrintResult myPrintResult = e.PrintResult; // Test is we have valid return PrintResults. if (myPrintResult != null) { // Get any messages returned from ArcGIS Server (add your own enhancements if desired). List<ESRI.ArcGIS.Client.Tasks.GPMessage> myListOfGPMessage = myPrintResult.Messages; // This is the userToken Parameter of the ExecuteAsync(printParameters,userToken) object myUserState = e.UserState; // Update the status informational messages. ListBox_StatusInformation.Items.Add("The PrintTask was completed for: " + myUserState.ToString()); // Get the location of the image/.pdf created by ArcGIS Server. System.Uri myUri = myPrintResult.Url; // Open a new internet browser window with the generated image from the PrintTask. System.Windows.Browser.HtmlPage.Window.Navigate(myUri, "_blank"); } } private void Button_CancelAsync_Click(object sender, System.Windows.RoutedEventArgs e) { // This will cancel the ExecuteAsync operation. _PrintTask.CancelAsync(); // Update the status informational messages. ListBox_StatusInformation.Items.Add("The PrintTask was canceled."); } |
VB.NET | Copy Code |
---|---|
' Create a Global (aka. Member) variable for the PrintTask object that will be used in other ' parts of the application. Private _PrintTask As ESRI.ArcGIS.Client.Printing.PrintTask Public Sub New() InitializeComponent() ' Provide a valid PrintTask.Url for a "synchronous geoprocessing task" TextBox_Url.Text = "http://localhost:6080/arcgis/rest/services/Utilities/PrintingTools/GPServer/Export20Web20Map%20Task" ' Set the _PrintTask variable to a new instance of the PrintTask Class. _PrintTask = New ESRI.ArcGIS.Client.Printing.PrintTask() ' Prevent the internet browser from using a cache for the PrintTask operations. _PrintTask.DisableClientCaching = True ' Set the PrintTask.Url from what is entered in the TextBox. _PrintTask.Url = TextBox_Url.Text ' Wire up an Event Handler for the PrintTask.ExecuteCompleted Event. AddHandler _PrintTask.ExecuteCompleted, AddressOf printTask_ExecuteCompleted End Sub Private Sub Button_ExecuteAsync_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) ' Define the settings for rendering the image/.pdf on the ArcGIS Server. ' Define the ExportOptions. Dim myExportOptions As New ESRI.ArcGIS.Client.Printing.ExportOptions myExportOptions.Dpi = 96 '96 DPI is typical Window OS setting. myExportOptions.OutputSize = New Size(MyMap.ActualWidth, MyMap.ActualHeight) ' Use the dimensions of the Map ' Define the PrintParameters. Dim myPrintParameters As New ESRI.ArcGIS.Client.Printing.PrintParameters(MyMap) myPrintParameters.ExportOptions = myExportOptions ' Use the ExportOptions defined earlier. myPrintParameters.LayoutTemplate = "MAP_ONLY" ' Look to the REST service to see what layout templates are supported. myPrintParameters.Format = "JPG" ' Look to the REST service to see what image formats are supported. ' NOTE: ' If you try to submit more that one 'synchronous geoprocessing task' via PrintTask.ExecuteAsync at a time ' using the ExecuteAsync methadology you will get a Visual Studio (Runtime) error: ' NotSupportedException was unhandled by user code. "Task does not support concurrent I/O operations. Cancel ' the pending request or wait for it to complete." ' In order to overcome this, use the PrintTask.IsBusy Property and take action accordingly. If _PrintTask.IsBusy = True Then ' There is an existing 'synchronous geoprocessing task' PrintTask running. ' Use a simple MessageBox to get user direction on whether to stay with the currently running 'synchronous ' geoprocessing task' PrintTask or cancel it and start another one. Dim myMessage As System.Windows.MessageBoxResult = MessageBox.Show("Click 'Cancel' to kill the prior print job and print this one OR click 'OK' to finish the prior " + "print job and wait to re-click the Print button.", "Action Required", MessageBoxButton.OKCancel) If myMessage = MessageBoxResult.Cancel Then ' The user has opted to cancel the currently runnning 'synchronous geoprocessing task' PrintTask. ' Kill the PrintTask. _PrintTask.CancelAsync() ' Clear out the status informational messages. ListBox_StatusInformation.Items.Clear() ' Create a UserToken to identify which PrintTask is running. Dim myToken As String = "MY TOKEN2" ' Use the 'synchronous geoprocessing task' PrintTask.ExecuteAsync Method. _PrintTask.ExecuteAsync(myPrintParameters, myToken) ' Update the status informational messages. ListBox_StatusInformation.Items.Add("The PrintTask was started.") ElseIf myMessage = MessageBoxResult.OK Then ' The user has opted to let the currently runnning 'synchronous geoprocessing task' PrintTask complete. ' Update the status informational messages. ListBox_StatusInformation.Items.Add("The PrintTask is busy (still processing).") End If ElseIf _PrintTask.IsBusy = False Then ' There is not and existing 'synchronous geoprocessing task' PrintTask running. ' Clear out the status informational messages. ListBox_StatusInformation.Items.Clear() ' Create a UserToken to identify which PrintTask is running. Dim myToken As String = "MY TOKEN" ' Use the 'synchronous geoprocessing task' PrintTask.ExecuteAsync Method. _PrintTask.ExecuteAsync(myPrintParameters, myToken) ' Enable button for the user to cancel the PrintTask request. Button_CancelAsync.IsEnabled = True ' Update the status informational messages. ListBox_StatusInformation.Items.Add("The PrintTask was started.") End If End Sub Private Sub printTask_ExecuteCompleted(sender As Object, e As ESRI.ArcGIS.Client.Printing.PrintEventArgs) ' Use only for ExecuteAsync operations (i.e. synchronous geoprocessing tasks). ' Get any error information (add your own enhancements if desired). Dim mySystemException As System.Exception = e.Error ' Get the PrintResult from the completed operation. Dim myPrintResult As ESRI.ArcGIS.Client.Printing.PrintResult = e.PrintResult ' Test is we have valid return PrintResults. If myPrintResult IsNot Nothing Then ' Get any messages returned from ArcGIS Server (add your own enhancements if desired). Dim myListOfGPMessage As List(Of ESRI.ArcGIS.Client.Tasks.GPMessage) = myPrintResult.Messages ' This is the userToken Parameter of the ExecuteAsync(printParameters,userToken) Dim myUserState As Object = e.UserState ' Update the status informational messages. ListBox_StatusInformation.Items.Add("The PrintTask was completed for: " + myUserState) ' Get the location of the image/.pdf created by ArcGIS Server. Dim myUri As System.Uri = myPrintResult.Url ' Open a new internet browser window with the generated image from the PrintTask. System.Windows.Browser.HtmlPage.Window.Navigate(myUri, "_blank") End If End Sub Private Sub Button_CancelAsync_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) ' This will cancel the ExecuteAsync operation. _PrintTask.CancelAsync() ' Update the status informational messages. ListBox_StatusInformation.Items.Add("The PrintTask was canceled.") End Sub |
Target Platforms: Windows XP Professional, Windows Server 2003 family, Windows Vista, Windows Server 2008 family, Windows 7, Windows 8