Do you have a process that you need to run in the background of Microsoft Dynamics 365 F&S? SysOperation Framework in D365 is made for doing this. In this article I will show you the quickest and simplest way of creating the needed classes.
When To Use SysOperation Framework in D365
First, what are some scenarios where you might want a process or job to run in the background?
- The most common scenario is that you have a set of records that you need to process or do some calculation for. Perhaps you have used a Data Entity or Service to bring data into a staging table. Now you need to loop through each record and create functional data inside the system. SysOperation Framework in D365 is made for just this sort of thing.
- Another scenario is that you have some process that you normally run on a single record in a form, but now you want to run the process on many records. SysOperation Framework in D365 can easily be setup to loop through a group of records and call existing code to process each record.
- Lastly, is a scenario that is often under used. You may have a button on a form that when clicked will run some process on a record. If that process does not run instantly and you do not need to immediately use the result of the process, you can offload that work to job that uses SysOperation Framework in D365. Perhaps running a single process only takes 15 seconds to run, but by letting the system do the work in the background you can improve the user experience greatly. Typically a user would have to wait those 15 seconds while the operation completes. But now they are given back control immediately and can continue working.
Create The Contract
The contract class contains any data we need to directly send to the process. Create a new class in D365, with the attribute [DataContractAttribute] at the top. And by convention the name of the class should end with the word ‘Contract’. Add member variables and parm methods for each value that needs to be passed to the process doing the work. Perhaps you have a From Date and To Date that you are running the process for. In the simplest SysOperation Framework scenarios, this class can be left blank.
[DataContractAttribute]
class rsmTutSysOperationsContract
{
}
Create The Service
The service class contains the code that actually performs the processing. Create a new class in D365, that extends the class SysOperationServiceBase. Also, by convention, the name of the class should end with the word ‘Service’. Create a public method, named whatever you would like, that takes a single parameter which is of the type of the Contract class.
class rsmTutSysOperationsService extends SysOperationServiceBase
{
public void process(rsmTutSysOperationsContract _contract)
{
//Do something
}
}
Create The Controller
The controller class really just configures the SysOperation Framework process. Create a new class in D365, that extends the class SysOperationServiceController.
class rsmTutSysOperationsController extends SysOperationServiceController
{
}
Then add these four methods.
- Create a new method that calls super. It needs to pass a)The name of the Service class, the name of the method on the service Class, and the execution mode.
protected void new()
{
super(classStr(rsmTutSysOperationsService), methodStr(rsmTutSysOperationsService, process), SysOperationExecutionMode::Synchronous);
}
2. Create a method named ‘defaultCaption’. This will override the base method and return the name of the job.
public ClassDescription defaultCaption()
{
return "Process Job";
}
3. Create a method named ‘construct’. This will instantiate the controller class and set the execution mode.
public static rsmTutSysOperationsController construct(SysOperationExecutionMode _executionMode = SysOperationExecutionMode::Synchronous)
{
rsmTutSysOperationsController controller;
controller = new rsmTutSysOperationsController();
controller.parmExecutionMode(_executionMode);
return controller;
}
4. Lastly, create a method named ‘main’. The main method is always called by the menu item. This method will call ‘startOperation’ which actually calls the Service class’s method to do the work.
public static void main(Args _args)
{
rsmTutSysOperationsController controller;
controller = rsmTutSysOperationsController::construct();
controller.parmArgs(_args);
controller.startOperation();
}
Create The Action Menu Item
Create a new action menu item that will call the controller class. In my example, the controller class is named rsmTutSysOperationsController. So I will name my action menu item the same thing. In the Properties, set the ‘Object Type’ to be Class, and the ‘Object’ to be name of the controller class.
Set the Label in the menu item properties.
Then add the menu item to an appropriate menu.
Parameters, Defaults, Validation, Mandatory and UIBuilder
Please see these other articles for more advanced SysOperation Framework functionality.
First, learn how to add parameters to your batch jobs. D365 SysOperation Framework Parameters
Next, override the drop-downs to show only validate options. D365 SysOperation Framework Override Lookups
After adding parameters to a SysOperation Framework batch job, you may want to set those parameters to start with an initial value. Learn how to set a D365 SysOperation Framework default value.
Additionally, add validation to the parameters. D365 SysOperation Framework Validation
Lastly, learn to add D365 SysOperation Framework mandatory parameters that show a red outline and a star to indicate the field must be populated.
For another great reference on how to create classes using the SysOperation Framework in D365, see this article.
Conclusion
The ability to let the system run processes in the background and allow the user to continue with their work in incredibly useful. It is also very easy to setup and use. These jobs can scheduled to run on a reoccurrence, or they can be run a single time. I hope that this article, and these jobs, will save you some time.
What’s up, after reading this awesome post i am as well delighted tto share my experience here with friends.
I do not even knpw hhow I ended up here, but I thought this post was great.
I don’t know wwho you are but certainly you are going to a famous blogger if yoou are not
already 🙂 Cheers!
Very nice post. I just stumbled upon your blog and wanted
tto say that I’ve truly enjoyed surfing around ylur
blog posts. In any case I will be subscribing to your feed and I hope
you write again very soon!
Very good post Peter. This helped me a lot.
I am so glad. Thanks for your comment Zach! Sorry for the slow reply.
Awesome!!!!!!!! superb explaination. i also want to know how to disable the run in background or batch proccessing when a user clicks on a newly created button in a form and it should opens a ssrs report with run in background as disabled…please write an article on tghis.
Thanks Harish for your comment! I will see what I can around this topic. Thanks for the suggestion.
Hello Peter,
Excellent Video, your posts helped me a lot…
I am a student, learning about x++, can you say to me what am i doing wrong? my problem is in the class nameClassContract, when i put extends SysOperationServiceBase, it give me a warning: SysOperationServiceBase does not exist
What i need to do? Thanks!
Include the Reference in your Model for SysOperationServiceBase
Hello peter,
Very nice post…Pls add one more article with adding multithreading concept in sys operation.
Sounds good! I will work on that.
Thanks for this awesome blog. All of these posts are so incredibly useful, I really appreciate it and love the care you take to lay these concepts out so clearly.
Thank you so much for this. This means a lot to me! Thank you.
Hi Peter,
I have a question about creating a batch job using SysOperationgFramework that I’m wondering if you know the answer to. If I add multiple tasks that operate in parallel, is there any way to make the results of those batch tasks all commit or abort as a single unit? In other words, if I have an error in one task, can I roll the database changes of all of the tasks back? I figured there must be a way to do this but I couldn’t identify any good approach to handling it.
This is a good question. I would need to double check. I believe you should be able to put a ttsbegin and ttscommit around the whole code that creates and runs the multiple threads. Then, if any one of them throws an error, the system should revert all data pack to the state it was in when the ttsbegin line was run.
I will try to write an article on how to create a multi-threaded (multi-task) batch job, and see if I can test this out.
Thanks! The more I looked into it, I don’t believe it is possible without doing some very awkward and possibly dangerous practices that could open up to infinite loops or deadlocks. What I was able to find out is that each batch task has its own transactional scope and there was no way for me to wrap all of the tasks in a single tts block. In my case, I had to change my approach to allow the tasks to complete independently and move forward with handling the repercussions of this. Thanks again for your great articles!