Asynchronous Operations: General Information
An instance of a graph is created on each round trip to process a request created by the user on the appropriate form. After the request is processed, the graph instance must be cleared from the memory of the MYOB Acumatica server. If you implement code that might require a long time to execute an action or to process a document or data, you should execute this code asynchronously in a separate thread.
In this chapter, you will learn how to run an operation asynchronously by using the PXLongOperation class.
Learning Objectives
In this chapter, you will learn how to do the following:
- Implement a long-running action
- Create the associated button on the table toolbar for the long-running action
- Set up the long-running action to execute asynchronously by using the PXLongOperation class
Applicable Scenarios
You set up an operation to run asynchronously when this operation is expected to take a long time to finish its execution.
Use of the PXLongOperation Class
To make the system invoke the method in a separate thread, you can use the PXLongOperation.StartOperation method. Within the method that you pass to StartOperation, you can, for example, create a new instance of a graph and invoke a processing method on that instance. The following code snippet demonstrates how you can execute code asynchronously as a long-running operation in a method of a graph.
PXGraph.CreateInstance<T>()
method. Do not use the new
T()
graph constructor because in this case, no extensions or overrides of the
graph are initialized.public class MyGraph : PXGraph
{
...
public void MyMethod()
{
...
PXLongOperation.StartOperation(this, delegate()
{
// insert the delegate method code here
...
GraphName graph = PXGraph.CreateInstance<GraphName>();
foreach (... in ...)
{
...
}
...
});
...
}
...
}
If you need to save data to the database inside a long-running operation, call the Save.Press() method of the current graph. We do not recommend that you use the Actions.PressSave() method because it performs an external call and should be used from the UI only.
The following code shows an example of a method called InvoiceOrder
that
is to be executed asynchronously. This method is being called within the delegate that you
pass to PXLongOperation.StartOperation()
method.
PXLongOperation.StartOperation(this, delegate ()
{
InvoiceOrder(graphCopy);
});
The PXLongOperation.StartOperation()
method creates a separate thread and
executes the specified delegate asynchronously on this thread. The method passed into
PXLongOperation.StartOperation()
matches the following delegate type,
which has no input parameters.
delegate void PXToggleAsyncDelegate();
(delegate())
is used to
shorten the code in the example.Inside the delegate()
method, you should not use members of the current
graph, because this would lead to synchronous execution of the method. Instead, use a copy
of the graph, which you can create by using the var graphCopy =
this.Clone();
statement.
Use of the Custom Information Dictionary
In the delegate method of a long-running operation, you can store a data object in the _CustomInfo dictionary of the long-running operation and get the list of records processed by the method. You can add to the dictionary any data object needed for a long-running operation by using a SetCustomInfo method.
For a processing operation, the system stores the PXProcessingMessagesCollection<TTable> list of messages in the dictionary. Each message in the list is of the PXProcessingMessage type, which includes a string message and an error level that is of the PXErrorLevel type.
See New way to work with CustomInfo of PXLongOperation at http://asiablog.acumatica.com for more information about the use of the dictionary.