Asynchronous Operations: To Implement an Asynchronous Operation
The following activity will walk you through the process of implementing a long-running action and executing it asynchronously.
Story
Suppose that you need to create an action that allows users to validate the prices for the repair items added in the table on the Repair Items tab of the Services and Prices (RS203000) form, in the PhoneRepairShop customization project. Suppose that you need to validate the prices by using an external service. This action can potentially take a long time to finish its execution and hence it should be executed asynchronously. You need to define an action in the graph of the form and configure the associated button (on the table toolbar). You need to define the code that will be used to perform the validation of the prices and execute this code asynchronously by using the PXLongOperation.StartOperation method.
Process Overview
- Adding the
IsPriceValidated
field that you added in Step 3 of Test Instance for Customization: To Deploy an Instance for Creating Actions to theRSSVRepairItem
DAC, and updating the ASPX file of the Services and Prices (RS203000) form. This will make this field visible as the Price Validated column, in the table on the Repair Items tab of the form. - Defining the logic needed to validate the prices of the repair items in a
method called
ValidatePrices
, implementing theValidateItemPrices
action and setting it up the to run theValidatePrices
method asynchronously, and creating the associated Validate Prices button on the table toolbar. - Testing the Validate Prices button and the underlying action.
System Preparation
Step 1: Updating the Services and Prices (RS203000) form to Display the Price Validated Column and the Validate Prices Button
IsPriceValidated
field to the
RSSVRepairItem
DAC and update the corresponding ASPX file to
respectively show the Price Validated column in the table,
and the Validate Prices button on the table toolbar of the
Repair Items tab, do the following:- Add the following code to the
RSSVRepairItem.cs
file after theBasePrice
field definition.
Note that the field is set to be disabled on the UI because this field is meant to be updated by an external service. The field is set to#region IsPriceValidated [PXDBBool] [PXDefault(false)] [PXUIField(DisplayName = "Price Validated", Enabled = false)] public virtual bool? IsPriceValidated { get; set; } public abstract class isPriceValidated : PX.Data.BQL.BqlBool.Field<isPriceValidated> { } #endregion
false
by default. - In the RS203000.aspx file, do the following:
- Add the following code inside the
<Columns>
tag of the<px:PXGridLevel DataMember="RepairItems" >
tag.
This code has added the Price Validated column, which is represented by the<px:PXGridColumn Type="CheckBox" DataField="IsPriceValidated" Width="100" > </px:PXGridColumn>
IsPriceValidated
DAC field, to the table on the Repair Items tab. - Add the following code in the
<px:PXTabItem Text="Repair Items">
tag after theLevels
closing tag.
In this code, you have defined an action bar on the table toolbar of the Repair Items tab and have added the Validate Prices button to it.<ActionBar> <CustomItems> <px:PXToolBarButton Text="ValidateItemPrices"> <AutoCallBack Command="ValidateItemPrices" Target="ds" /> </px:PXToolBarButton> </CustomItems> </ActionBar>
- Add the following code inside the
- Save your changes.
Step 2: Defining the Logic Used to Validate Prices
You should define the method in which the repair items prices are validated, and then
you can call this method in the PXLongOperation.StartOperation
method.
Since the objective of this activity is to execute a long-running operation
asynchronously by using the PXLongOperation.StartOperation
method, you will not be focusing on the specifics of the logic of the long-running
operation itself —that is, you will not be writing the code for connecting to
an actual external service, making a request and parsing the received result.
Instead, you will use the Thread.Sleep()
method to create a delay
in the execution of the method to simulate connecting to an external service. You
will simply pass the repair items to the ValidatePrices
method and
set the IsPriceValidated
field for each repair item to
true
. This will change the state of the check box in the
Price Validated column of the Repair
Items tab to be selected for each repair item and simulate a
successful validation from an external service.
To define the method in which the repair items prices are validated, do the following:
- Add the following
using
directives to theRSSVRepairPriceMaint.cs
file (if they have not been added yet).using System.Collections; using System.Collections.Generic; using System.Threading;
Tip:Instead of adding theusing
directives manually, you can add them with the help of the Quick Actions and Refactorings feature of Visual Studio after you define the method in the next instruction. - Add the following static method,
ValidatePrices
, to theRSSVRepairPriceMaint
graph. TheValidatePrices
method validates the repair items prices for the selected record on the Services and Prices (RS203000) form.private static void ValidatePrices(RSSVRepairPrice repairPriceItem) { /* Create an instance of the RSSVRepairPriceMaint graph and set the Current property of its RepairPrices view.*/ var priceMaint = PXGraph.CreateInstance<RSSVRepairPriceMaint>(); priceMaint.RepairPrices.Current = priceMaint.RepairPrices. Search<RSSVRepairPrice.serviceID, RSSVRepairPrice.deviceID> (repairPriceItem.ServiceID, repairPriceItem.DeviceID); /* Set a delay to mimic connecting to an external service to validate the repair item prices. In a real world scenario, you would connect to an actual external service and make an API request to validate the prices for the repair items.*/ Thread.Sleep(3000); /* Update the Price Validated field for each repair item on the Repair Items tab: Here we are assuming that the validation was successful from the external service and are setting IsPriceValidated to true for each repair item.*/ foreach (RSSVRepairItem item in priceMaint.RepairItems.Select()) { // Set IsPriceValidated to true for each repair item. item.IsPriceValidated = true; // Update the cache with the above change for each repair item. priceMaint.RepairItems.Update(item); } /*Trigger the Save action to save the changes stored in the cache to the database.*/ priceMaint.Actions.PressSave(); }
In the method above, you first create an instance of the
RSSVRepairPriceMaint
graph. You then set the current property
of the RepairPrices
view of this graph instance to the parameter of
type RSSVRepairPrice
that was passed into the
ValidatePrices
method.
You then use the Thread.Sleep(3000)
method call to pause the
execution of the method to simulate a long-running operation that is connecting to
an external service. You then loop through each repair item of the selected record
on the Services and Prices form and set its IsPriceValidated
property to true
to indicate that its price has been validated.
Finally, you update the cache and save the changes to the database.
Step 3: Defining the ValidateItemPrices Action
The ValidateItemPrices
action defines the underlying action for the
Validate Prices button on the table toolbar of the
Repair Items tab, and invokes the
PXLongOperation.StartOperation method that executes the
ValidatePrices
method added in Step 2, asynchronously.
To define the ValidateItemPrices
action, add the following code to
the RSSVRepairPriceMaint
graph.
#region Actions
public PXAction<RSSVRepairPrice> ValidateItemPrices;
[PXButton(DisplayOnMainToolbar = false, CommitChanges = true)]
[PXUIField(DisplayName = "Validate Prices", Enabled = true)]
protected virtual IEnumerable validateItemPrices(PXAdapter adapter)
{
// Populate a local list variable.
List<RSSVRepairPrice> list = new List<RSSVRepairPrice>();
foreach (RSSVRepairPrice repairItemPrice in adapter.Get<RSSVRepairPrice>())
{
list.Add(repairItemPrice);
}
// Trigger the Save action to save changes in the database.
Actions.PressSave();
var repairPriceItem = RepairPrices.Current;
/*Execute ValidatePrices method asynchronously
using PXLongOperation.StartOperation*/
PXLongOperation.StartOperation(this, () => ValidatePrices(repairPriceItem));
// Return the local list variable.
return list;
}
#endregion
In the ValidateItemPrices
method, you compose a list of services and
prices by using the adapter.Get method, and invoke the
Actions.PressSave action. Because the return of the
adapter.Get method does not include data that has not been
saved on the form, by calling the PressSave method, you update
the records in the composed list.
Then you use the PXLongOperation.StartOperation()
method to validate
the prices of the repair items on the Repair Items tab for
the record that is selected on the Services and Prices (RS203000) form. You do this
by invoking the ValidatePrices
method within the method that you
pass to StartOperation().
Finally, you return the list of services and prices.
Step 4: Testing the Validate Prices Button and the Associated Action
To test the Validate Prices button and the underlying action, do the following:
- Rebuild the
PhoneRepairShop_Code
project in Visual Studio, and publish the customization project in the Customization Project Editor. - In MYOB Acumatica, open the Services and Prices (RS203000) form.
- Open any services and prices record —that is, any services
and prices record that does not have the check box selected in the
Price Validated column for any of the repair items on
the Repair Items tab.
Notice that the Validate Prices button is available on the table toolbar of the Repair Items tab.
- On the table toolbar, click Validate Prices.
A notification appears indicating the status of the processing, as shown in the following screenshot.
When the process is complete, the check box for each repair item is selected in the Price Validated column of the Repair Items tab, as shown in the following screenshot.