Most of the time when debugging x++ code, you can debug the current process. However sometimes code is written in such as way that certain code branches will only be run when the process is running as a batch job. In this article, I will teach you how to debug batch jobs in D365.
The Short Answer
If you already know where to put a breakpoint, then the short answer on how to debug batch jobs is to attach to the Batch.exe service. However, before you can do this, you need to be able to understand what batch job class is running. And where in that class to put a breakpoint. The rest of the article will explain how to do that.
Determine What Batch Job Is Running
Most of the time, you are told that a user is running a menu item in D365, and that the menu item runs a batch job. Yet the batch job is not doing what is supposed to. So you are asked to investigate and debug the batch job. But to start, you need to know what class you need to put a breakpoint in. Let’s look at a couple different ways you can do this. There are many ways. This is just some common ways.
Batch Job Vs Sys Operations Framework
Before we talk about that, I wanted to clarify one thing first. In this article, when I refer to batch jobs, I am referring to all jobs that you can find in the ‘Batch jobs’ form. These are jobs that run behind the scenes, and do not run on the current user’s process. These jobs are useful because they allow the user to continue to use the system while the process is running in the background. If the job where to be run on the user’s process, the user will not be able to perform any action until the job finished. And for processes that take a long time to run, this would not be a good user experience.
In Microsoft Dynamics 365 for Finance and Operations, the system still supports batch jobs that are build using classes that extend the base class RunBaseBatch. However now, it is recommended the developers build their batch jobs uses SysOperation Framework. See my other article on how to build a SysOperation Framework batch job. While these two jobs are built using different code, they still have the system run their processes entirely on the server. And can be scheduled to run independent of the user interface. In this article, for simplicity sake, we will call both of these ‘batch jobs’.
Right Click Form Information
Navigate to the menu item that you have been told that runs the batch job. For example, there is a batch job that can invoice sales orders. This menu item is found by navigating to Accounts receivable>Invoices>Batch invoicing>Invoice. When you run this menu item in D365, a dialog will open.
In order to figure out which x++ class is being called, right click anywhere on the dialog, and select Form information>Form Name: <Name of form>.
When you do this, a dialog will open. There will be a fast tab labeled ‘Administration’. Expand this fast tab, and scroll until you see the fields labeled ‘Caller name’ and ‘Caller type’. In the case of batch jobs, this will usually be a class.
Next, make note of the class specified on the Caller name field. In my example it is the class SalesFormLetter_Invoice. Great, we know the class we need to put a breakpoint in!
Before we do that, I will explain another way you can figure out what class is being called.
Find The Menu Item
Another way to find the class being called as part of the batch job, is to look at the menu item. In my example, the user is running the menu item Accounts receivable>Invoices>Batch invoicing>Invoice.
Open Visual Studio, and open the Application Explorer. If you do not see the Application Explorer window, you can open it by selecting View>Application Explorer. Next, expand the ‘User Interface’ node and then the Menus node. This node shows all of the top level menus in the system. For my example, locate ‘AccountsReceivable’.
For my example it is pretty clear by the name of the menu object which menu it relates to. But if you are unsure, you can always right click on the object, and select properties. Then look at the ‘Label’ to validate that the label matches what you are seeing when running D365 from a browser. This is true for all the subMenus and menu items beneath these folders as well.
Next, expand the AccountsReceivable node, the Invoices node, and the BatchInvoicing node. Finally select the SalesFormLetter_Invoice node, right click and select Properties.
In the Properties window, locate the MenuItemName and MenuItemType. In my example, the MenuItemName is ‘SalesFormLetter_InvoiceMainMenuWrapper’. And the MenuItemType is ‘Action’.
As long as the batch job is following batch practices, it should always be called by a menu item of type ‘Action’. Navigate to the Action menu items in the Application Explorer, or search for the menu item using the search bar at the top of the Application Explorer window.
View The Object Property On the Menu Item
Once you have located the menu item, right click on it, and select Properties. In the Properties window, locate the properties ‘Object’ and ‘ObjectType’.
This shows us that the menu item is calling the class named ‘SalesFormLetter_InvoiceMainMenuWrapper’. Note: It is very common to name the menu item the same as the object being called. So sometimes after you know the name of the menu item, you can just assume it is the same and perform a search. But if you are not finding it, it is best to check the properties on the menu item specifically.
Typically, the class that is being called by the menu item is the class that is the batch job. In this case, this class just calls another menu item named ‘SalesFormLetter_Invoice’, which calls the class ‘SalesFormLetter_Invoice’.
Where To Add A Breakpoint For RunBaseBatch
In order to know where to put a breakpoint, we need to determine whether the class extends RunBatchBase or SysOperationServiceController.
When a class extends RunBaseBatch, the class will have a ‘main’ method and a ‘run’ method. The ‘main’ method is run only when the user calls the batch job from the menu item. This causes the system to first show the dialog form. But when a batch job actually runs behind the scenes as a batch job, it will call the ‘run’ method. So you will want to put your code in the ‘run’ method or some method called by the run method.
Where To Add A Breakpoint For SysOperation
In my example, I can see in the class declaration that the class SalesFormLetter_Invoice extends SalesFormLetter. When I looked, I found SalesFormLetter extends FormLetterServiceController. And FormLetterServiceController extends SysOperationServiceController. Most of the time, it is not this complicated. I picked one of the most complicated for an example.
When your class extends SysOperationServiceController, you need to look at the ‘new’ method. And see the name of the ‘method’ that is passed as the second parameter into the call to ‘super’.
In our example, the new method looks like this. This lets us know that the system will be calling the postSalesOrderInvoice method on the FormLetterService class.
This method shows that it will call the ‘run’ method on the class.
So we can finally add a breakpoint to the ‘run’ method by selecting that line and pressing F9. Or clicking on the grey bar just to the left of the line of code.
Again, we probably looked at the most complicated example. Typically you can look at the new method on the same class to see what method is being run. And if you see that there is a method on the class called ‘run’ or ‘process’, and you are feeling lucky, you can just put a breakpoint there, and see if it gets called. Then look at the call stack to understand the flow of code.
Attaching To The Batch Process
Finally, let’s look at how to debug batch jobs. Go to view Debug>Attach to Process…
In the dialog that opens, make sure ‘Show processes from all users’ is checked. Then select ‘Batch.exe’ from the list.
Click Attach.
Now you must wait until the batch job runs in batch. If you run the batch job directly without checking ‘Run in Background’ the job will run under iisexpress.exe or w3wp.exe. So when you run the job, you need to ensure ‘Run in Background’ is checked.
Once the system starts the batch job, your breakpoint will hit, as long as your breakpoint symbols loaded properly.
From there, you can step through the code and determine if there is an issue.
Conclusion
Most of the time, if you need to debug a job, it is recommended you run the job, and simply uncheck the ‘Run in Background’ checkbox. This way, you can run the class as a Startup Object in Visual Studio and just push F5. Or you can attach to the iisexpress or w3wp processes. This saves you time as you do not need to wait for the system to start running the batch job. It will run right away.
However, there are still many batch jobs that have code that only runs when running in the Batch service. And there is code that can behave differently when running in the Batch service. So it is still very useful to understand how to debug batch jobs in Microsoft Dynamics 365 for Finance and Operations.