SysOperation Framework cheat sheet

The SysOperation Framework is a framework that Microsoft introduced in AX 2012. It is largely unchanged in Microsoft Dynamics 365 For Operations and Finance. Unless one works with it on a regular basis, the steps are easily forgotten. Here is a cheat sheet to help.

See the references at the end of this post for links to more information.

1. Create the contract

  • Create a class (example: FooContract) with the DataContractAttribute attribute.
  • Add member variables for values being passed to the service.
  • For each member variable, create a parameter method (example: parmBar()) with the DataMemberAttribute attribute.
    • Include the SysOperationControlVisibilityAttribute attribute for hidden parameters.
    • Include SysOperationLabelAttribute attribute to change the label of a parameter.

2. Create the service

  • Create a class (example: FooService) that extends SysOperationServiceBase
  • Add a public method for the entry point (example: process())
    • In AX 2012, include the SysEntryPointAttribute attribute (this attribute is obsolete in D365FO).
    • The method has a single parameter which is the contract. For example:
public void process(FooContract _contract)
{
    // process something
}

3. Create the controller

In theory, the controller class is not required. However, one is needed for processing arguments from menu items and setting values on the contract. IMHO, it is best to have one.

  • Create a class (example: FooController) that extends SysOperationServiceController
  • Override the new() method and call super() similar to the following.
protected void new()
{
    super(classStr(FooService), methodStr(FooService, process), SysOperationExecutionMode::Synchronous);
}
  • Override the defaultCaption() method and to return the name of the batch job as a string.
  • Add a construct() static method to create an instance of the controller. The construct() method is a good place to set parameters on the controller or to set values on the contract.
  • Add a main() static method that the system will call from a menu item.
    • Instantiate the controller using the construct() static method.
    • In the end, call the startOperation() method.

4. Add the controller to the menu

  • Create a menu item (example: FooController) that executes the controller class.
  • Add the menu item to the appropriate menu.
  • Add the menu item to a security privilege.

5. Create UI builder (if needed)

Most of the time, a UI builder is not needed. Most of the time, a developer would create one if one or more parameters require a custom lookup or to add logic to enable/disable fields.

  • Create a class (example: FooUIBuilder) that SysOperationAutomaticUIBuilder.
  • Override the build() method to add dialog fields not created from the contract.
    • Use the addDialogField() method to add a field.
    • Be sure to call super() to allow the creation of fields from the contract.
  • Override the postBuild() method to change the behavior of dialog fields
    • To find the contract, use the dataContractObject() method.
    • To access a control for a parameter, use the getDialogFieldControl() method on the object obtained from calling the bindInfo() method.
    • To override a method (such as lookup() or modified()) on a dialog field, use the registerOverrideMethod() on the dialog field control.
  • Include a SysOperationContractProcessingAttribute attribute that references the UI builder class to the contract class.

Multiple batch tasks

Depending on the domain of the batch job being developed, it might not be necessary to add support for multiple tasks. In general, developers use multiple batch tasks to process items in parallel (using multiple threads). The most common usage is processing large data sets.

The process for adding support for multiple batch tasks is nearly identical creating a batch job. When writing the batch job, its role is to collect the data for processing and to split that data among the batch tasks it creates. The role of the batch task is to process the data assigned to it.

6. Create the batch task contract

The procedure for this contract is the same as above (example: FooTaskContract). The data that the developer will pass using this contract is the information needed to identify the data set on which the batch task will run.

7. Create the batch task service

Like the batch task contract, the procedure for the batch task service is the same as above (example: FooTaskService). The role of the service class is to take the data set identified by the batch task contract and process it.

8. Create batch tasks

In the main service class (example: FooService), when it finishes allocating data for tasks to process, it needs to create the batch tasks. An example of a method could be similar to the following.

private void addBatchTasks()
{
    if (this.isExecutingInBatch())
    {
        BatchHeader header = this.getCurrentBatchHeader();

        for (int i = 1; i <= conLen(batchTasksList); i++)
        {
            str batchTaskId = conPeek(batchTasksList, i);

            SysOperationServiceController controller = new SysOperationServiceController(classStr(FooTaskService), methodStr(FooTaskService, process));
            FooTaskContract contract = controller.getDataContractObject() as FooTaskContract;
            contract.parmBatchTaskId(batchTaskId);

            header.addRuntimeTask(controller, this.getCurrentBatchTask().RecId);
        }

        header.save();
    }
    else
    {
        str batchTaskId = conPeek(batchTasksList, 1);
        FooTaskService::construct().process(batchTaskId);
    }
}

References

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s