Although you’ll still see it in many solutions, x++ runbasebatch is the legacy pattern for background work: a single class (with dialog, pack/unpack, and run()) that you can schedule on a batch server. It’s fine for extending existing features, but new development is usually cleaner with the SysOperation pattern. Think of RunBaseBatch as the “all-in-one tool” that works, but doesn’t separate parameters from execution logic.
Practically speaking, how to create batch job in d365 x++ with RunBaseBatch means: override dialog() to add fields, use getFromDialog() to read them, persist settings with pack()/unpack(), and place your business logic in run(). You then expose the class via a menu item and let users tick “Run in the background” (or schedule it with a recurrence) so it lands in System administration > Batch jobs.
For new work, create batch job using sysoperation framework in d365 by splitting responsibilities: a [DataContractAttribute] class for parameters, a Service class with the operation method, and (optionally) a Controller to launch it. This separation makes unit testing easier, parameters self-documenting, and batch persistence automatic. You’ll mark each parm with [DataMemberAttribute], provide friendly labels, and let the runtime render a dialog that users can run once or schedule.
Even if you’ve learned x++ runbasebatch, the modern SysOperation example below shows the same warehouse scenario—relabelling ESD-sensitive storage locations for electronics—implemented with a Data Contract and Service:
// Data Contract (dialog parameters)
[DataContractAttribute]
class EsdRelabelContract
{
WareHouseId warehouseId;
EcoResProduct productNumber;
boolean dryRun = true;
[DataMemberAttribute('Warehouse')]
public WareHouseId parmWarehouseId(WareHouseId _v = warehouseId)
{
warehouseId = _v; return warehouseId;
}
[DataMemberAttribute('ProductNumber')]
public EcoResProduct parmProductNumber(EcoResProduct _v = productNumber)
{
productNumber = _v; return productNumber;
}
[DataMemberAttribute('DryRun')]
public boolean parmDryRun(boolean _v = dryRun)
{
dryRun = _v; return dryRun;
}
}
// Service (business logic; can run in batch)
class EsdRelabelService
{
[SysEntryPointAttribute]
public void run(EsdRelabelContract _c)
{
if (!_c.parmWarehouseId())
throw error("Select a warehouse.");
InventLocation loc;
while select forupdate loc
where loc.Warehouse == _c.parmWarehouseId()
{
str newLabel = strFmt("ESD-SAFE-%1", loc.LocationId);
if (_c.parmDryRun())
{
info(strFmt("Would relabel %1 -> %2", loc.LocationId, newLabel));
}
else
{
ttsbegin;
// Replace with your actual field(s) for labeling/profile
loc.LocationProfileName = newLabel;
loc.update();
ttscommit;
info(strFmt("Relabeled %1 -> %2", loc.LocationId, newLabel));
}
}
}
}
Finally, when you create batch job using sysoperation framework in d365, launch the Service with a controller or menu item and encourage good habits: sensible defaults in the contract, clear labels/tooltips, and lightweight validation (e.g., “warehouse required,” “product filter optional”). For anything date-effective (prices, handling rules), pair this with validTimeStateUpdateMode(...) where appropriate, and prefer SysOperation for maintainability while reserving RunBaseBatch for legacy extensions or quick utilities.
Have a Question ?
Fill out this short form, one of our Experts will contact you soon.
Call Us Today For Your Free Consultation
Call Now