For those of us who have developed on earlier versions of AX, RunBaseBatch rings a bell. In fact, it was the primary ( and frankly is still used by Microsoft in 2012 R3 ) means of scheduling code execution. It could be an hourly process to invoice sales orders, a nightly MRP run, or a complex financial consolidation. The problem was it still had to execute in native X++ albeit on the Server tier, and if you had an external application that also needed to execute the same logic you had to build an extra interface.
Thankfully, this is no longer the case. With AX 2012 RTM, Microsoft released the SysOperation Framework (http://msdn.microsoft.com/en-us/library/gg862488.aspx ). SysOperation can prompt users for input in the Client tier, and then marshal the data over to a service for Server side execution via Batch processing. The code executes in CIL of which is much faster than native X++, and services can be exposed to external consumers for 3rd party integrations using the same logic. Can you say two birds with one stone?
A recent example, was a form previously developed in RunBaseBatch. It allowed the checkout of items from inventory via posting various movement journals based on the type of item selected. The logic behind which items posted to which journal needed to be configurable by the Finance department, and to make the lives of production personnel easier a form was created for the checkout process.
The form itself only had the datasources for InventDim and InventSum, so we had to use a little trick to load in the Financial Dimensions.
In some cases we also have 3rd party applications which check out stock from AX. To streamline the process, we converted the form to run via the SysOperation framework. To do this, we had to create a few objects:
A Service class with a service operation method. We required to pass in a list of Decrement objects, and return any of those that fail:
A data contract class that would be passed into the service operation, and represents a Decrement object:
Each variable requires a parm() method to capture the values of the calling user or application. It also implements SysPackable so that it can be transferred across tiers from the Client to the Server in the case where this is populated via our AX form.
Another data contract class for our service operation return value, of which is a list of Failed Decrement objects:
Each variable requires a parm() method and does not require implementing SysPackable in this case.
A controller class that extends from SysOperationServiceController, with a few overridden methods:
-- A static main method:
--A static constructor:
--The templateForm method:
We then build up the code behind our custom form template. The form needs to capture the data contract from the Controller, and populate it via edit methods on the form to fill the parm() methods on the data contract object. We then pass the contract back to the controller for transfer to the Server tier.
--The init() method of your template form:
Here we define a static macro for the name of our service operation parameter. This needs to match exactly as specified in your service method!
--The controller method:
--The dialog method:
When the user closes the form, the decrement populated on the form is packed using the SysPackable interface and automatically marshalled over to the Batch Processing framework. Based on the different settings for your menu item, you can specify if the service will execute in Batch, or simply Synchronously aka non-batch:
To expose this same decrement service operation via the AIF, one only need add a new Service node in the AOT connected to your class. Then, after the service is Registered ( right-click, add-ins, Register Service, hit the Refresh button ) you can deploy it via an inbound AIF port in the System Administration module.
There is a caveat to the inbound AIF port that we came across in this project, but it will warrant its own blog entry!
More to come soon!