Description:- SysOperation is a framework in Microsoft Dynamics® AX 2012 that
allows application logic to be written in a way that supports running
operations interactively or via the Microsoft Dynamics AX batch server. The
framework provides capabilities that are very similar to the RunBase framework
that came before it. The batch framework has very specific requirements for
defining operations:
1. The operation must support
parameter serialization so that its parameters can be saved to the batch table.
2. The operation must have a way to
display a user interface that can be launched from the batch job configuration
user interface.
3.
The
operation must implement the interfaces needed for integration with the batch
server runtime.
The RunBase framework defines
coding patterns that implement these requirements. The SysOperation framework
provides base implementations for many of the patterns defined by the RunBase
framework.
SysOperation and RunBase are frameworks geared toward building
operations that can run via the batch server or interactively. In order for an
operation to run via the batch server, it must meet these requirements:
1. It must support parameter
serialization via the SysPackable interface.
2. It must support the standard run
() method defined in the BatchRunable interface.
3. It must support the batch server
integration methods found in the Batchable interface.
4.
It must
provide a mechanism to show input parameters with a user interface.
Currently in Microsoft Dynamics AX, all operations that must run
via the batch server must derive from either the SysOperationController or
the RunBaseBatch base class.
The following two samples illustrate the basic capabilities
provided by the two frameworks:
1. SysOpSampleBasicRunbaseBatch
2.
SysOpSampleBasicController
The simplest operation based on
the
RunBaseBatch base class has to implement 12 overrides. The purpose
of this sample is simply to compare the RunBase and SysOperation frameworks.
For full details of the RunBase framework, see the following article on MSDN:
RunBaseBatch FrameWork
Create Class in Ax Classes node and Name it “SysOpSampleBasicRunbaseBatch”.
ClassDeclaration
- Derives from RunBaseBatch.
- Declares variables for operation input parameters.
- Declares variables for dialog box controls.
- Declares a macro defining a list of variables that need to be
serialized.
class SysOpSampleBasicRunbaseBatch extends RunBaseBatch
{
str text;
int number;
DialogRunbase dialog;
DialogField numberField;
DialogField textField;
#define.CurrentVersion(1)
#LOCALMACRO.CurrentList
text,
number
#ENDMACRO
}
Dialog
Populates the dialog box
created by the base class with controls needed to get user input. The initial
values from the class member variables are used to initialize the controls. The
type of each control is determined by the EDT identifier name.
protected Object
dialog()
{
dialog = super();
textField =
dialog.addFieldValue(IdentifierStr(Description255),
text,
'Text Property',
'Type some text here');
numberField =
dialog.addFieldValue(IdentifierStr(Counter),
number,
'Number Property',
'Type some number
here');
return dialog;
}
getFromDialog
Transfers the contents of
dialog box controls to operation input parameters.
public boolean
getFromDialog()
{
text =
textField.value();
number =
numberField.value();
return super();
}
putToDialog
Transfers the contents of
operation input parameters to dialog box controls.
protected void
putToDialog()
{
super();
textField.value(text);
numberField.value(number);
}
pack
Serializes operation input
parameters.
public container pack()
{
return [#CurrentVersion,
#CurrentList];
}
unpack
Deserializes operation input
parameters.
public boolean
unpack(container packedClass)
{
Integer version = conPeek(packedClass,1);
switch (version)
{
case #CurrentVersion:
[version,#CurrentList] =
packedClass;
break;
default:
return false;
}
return true;
}
run
Runs the operation. This
sample prints the input parameters via the Infolog. It also prints the tier
that the operation is running on and the runtime that is used for execution.
public void
run()
{
if (xSession::isCLRSession())
{
info('Running in a CLR session.');
}
else
{
info('Running in an interpreter session.');
if (isRunningOnServer())
{
info('Running
on the AOS.');
}
else
{
info('Running
on the Client.');
}
}
info(strFmt('SysOpSampleBasicRunbaseBatch: %1, %2',
this.parmNumber(), this.parmText()));
}
description
A static description for the
operation. This description is used as the default value for the caption shown
in batch and the operation user interface.
public static
ClassDescription description()
{
return 'Basic RunBaseBatch Sample';
}
main
The main interaction code for
the operation. This code prompts the user for input, and then runs the
operation or adds it to the batch queue.
public static
void main(Args args)
{
SysOpSampleBasicRunbaseBatch operation;
operation = new
SysOpSampleBasicRunbaseBatch();
if (operation.prompt())
{
operation.run();
}
}
parmNumber
Optional. It is a Microsoft
Dynamics AX best practice to expose operation parameters with the property
pattern for better testability and for access to class member variables outside
the class.
public int
parmNumber(int _number = number)
{
number = _number;
return number;
}
parmText
Optional. It is a best
practice to expose operation parameters with the property pattern.
public str
parmText(str _text = text)
{
text = _text;
return text;
}
After
it is implemented, the operation can be run by using the Go button on
the code editor toolbar.
If
an X++ class implements the main operation, it is automatically called by the
code editor. The sample’s main operation will prompt the user for input for the
operation when operation.prompt () is called. If the prompt returns true,
main calls operation.run () directly. If the prompt returns false,
the user either cancelled the operation or scheduled it via batch.
To
run the operation interactively, enter data on the General tab of the
operation user interface.
Make
sure that the Batch processing check box is cleared on the Batch tab.
Clicking OK
will run the
operation and print the following output to the Infolog window.
The Infolog messages show that the operation ran on the
server, because the sample class is marked to run on the server. The operation
ran via the X++ interpreter, which is the default for X++ code.
If you repeat the previous steps but select the Batch processing
check box on the Batch tab, the operation will to run via the batch
server. When the Batch processing check box is selected, the following
Infolog message is shown, indicating that the operation has been added to the
batch queue.
The operation may take up to a minute to get scheduled. After
waiting for about a minute, open the Batch job form
from the Application Object Tree (AOT).
Repeatedly update the form by pressing the F5 key, until the
job entry shows that the job has ended. Sorting by the Scheduled start
date/time column may help you find the operation if there are many job
entries in the grid. After you find the correct job, select it, and then click Log
on the toolbar.
Clicking Log
opens an Infolog
window indicating that the operation ran in a CLR session, which is the batch
server execution environment.
In summary, this sample shows the minimum overrides needed to
create an operation that can run either interactively or via the batch server
by using the RunBaseBatch base class.
SysOpSampleBasicController
The purpose of the SysOperation framework is to provide the
same capabilities as the RunBase framework but with base implementations for
common overrides. The SysOperation framework handles basic user interface
creation, parameter serialization, and routing to the CLR execution
environment. The following table of overrides shows the code needed to match
the functionality demonstrated for the RunBase-based sample in the previous
section.
The
SysOperation sample contains two classes: a controller class named SysOpSampleBasicController
and a data contract class named SysOpSampleBasicDataContract.
SysOpSampleBasicController should derive from SysOperationServiceController,
which provides all the base functionality for building operations; however,
there are a few issues with that class as it is shipped with Microsoft Dynamics
AX 2012, and these will be addressed in a future service pack. In the meantime,
to work around the issues, a new common class, SysOperationSampleBaseController,
is provided. Details of the issues worked around will be discussed at the end
of this paper.
Create
Class in Classes node and Name it SysOperationSampleBaseController.
classDeclaration
Derives from the framework
base class SysOpSampleBaseController.
Normally the operation should
derive from the SysOperationServiceController class. The sample base class
provides a few fixes for issues in that class.
class
SysOpSampleBasicController extends SysOpSampleBaseController
{
}
new
Identifies the class and
method for the operation. In the sample, this points to a method on the
controller class; however, in general, it can be any class method.
The framework will reflect on
this class/method to automatically provide the user interface and parameter
serialization.
void new()
{
super();
this.parmClassName(classStr(SysOpSampleBasicController));
this.parmMethodName(methodStr(SysOpSampleBasicController,
showTextInInfolog));
this.parmDialogCaption('Basic SysOperation
Sample');
}
showTextInInfolog
Prints the input parameters
via the Infolog. Also prints the tier that the operation is running on and the
runtime that is used for execution.
public void
showTextInInfolog(SysOpSampleBasicDataContract data)
{
if (xSession::isCLRSession())
{
info('Running
in a CLR session.');
}
else
{
info('Running in an interpreter session.');
if (isRunningOnServer())
{
info('Running
on the AOS.');
}
else
{
info('Running
on the Client.');
}
}
info(strFmt('SysOpSampleBasicController: %1, %2',
data.parmNumber(), data.parmText()));
}
caption
A description for the
operation. This description is used as the default value for the caption shown
in batch and the operation user interface.
public ClassDescription
caption()
{
return 'Basic
SysOperation Sample';
}
main
The main interaction code for
the operation. This code prompts the user for input, and then runs the
operation or adds it to the batch queue.
public static
void main(Args args)
{
SysOpSampleBasicController operation;
operation = new
SysOpSampleBasicController();
operation.startOperation();
}
Now Create a
Class from Classes node and name it “SysOpSampleBasicDataContract”.
classDeclaration
The data contract attribute is
used by the base framework to reflect on the operation.
[DataContractAttribute]
class SysOpSampleBasicDataContract
{
str text;
int number;
}
parmNumber
The data member attribute
identifies this property method as part of the data contract. The label, help
text, and display order attributes provide hints for user interface creation.
[DataMemberAttribute,
SysOperationLabelAttribute('Number Property'),
SysOperationHelpTextAttribute('Type some number >= 0'),
SysOperationDisplayOrderAttribute('2')]
public int
parmNumber(int _number = number)
{
number = _number;
return number;
}
parmText
The data member attribute
identifies this property method as part of the data contract. The label, help
text, and display order attributes provide hints for user interface creation.
[DataMemberAttribute,
SysOperationLabelAttribute('Text Property'),
SysOperationHelpTextAttribute('Type some text'),
SysOperationDisplayOrderAttribute('1')]
public Description255 parmText(str _text = text)
{
text = _text;
return text;
}
As
in the RunBase sample, the operation can be run by using the Go button
on the code editor toolbar.
The main class calls operation.startOperation(), which
handles running the operation synchronously or adding it to the batch queue.
Although operation.run() can also be called, this should be done only if
the data contract has been programmatically filled out. The startOperation method
invokes the user interface for the operation, and then calls run.
To
run the operation interactively, enter data on the General tab of the
operation user interface. The user interface created by the framework is very
similar to the one created in the RunBase sample.
Make
sure that the Batch processing check box is cleared on the Batch tab.
Clicking
OK will run the operation and print the following output to the Infolog
window.
The
Infolog messages show that, unlike in the RunBase sample, the operation ran in
a CLR session on the server. If you repeat the previous steps but select the Batch
processing check box on the Batch tab, the operation will run via
batch, just as in the RunBase sample.
The
operation may take up to a minute to get scheduled. After waiting for about a
minute, open the Batch job form from the AOT, as in the RunBase sample.
Repeatedly
update the form by pressing the F5 key, until the job entry shows that the job
has ended. Sorting by the Scheduled start date/time column may help you
find the operation if there are many jobs entries in the grid. After you find
the correct job, select it, and then click Log on the toolbar.
Clicking
Log opens an Infolog window indicating that the operation ran in a CLR
session, which is the batch server execution environment.
This
sample showed that the SysOperation framework can provide the same basic
functionality as the RunBase framework. In addition, it provides implementation
for common RunBase overrides, such as parameter serialization and user
interface creation. It also provides the capability to route synchronous
operations to a CLR session.