Using customs services is the most flexible and customized way to integrate with D365F&O. Custom services are created with X++ code and can be used for both data-based, and operation-based integrations.
In this post I will show you how to create a custom service in D365 f&o using x++ language. In order to create a custom service in D365, there are several objects we need to have.
Create the ‘Request’ object.
We need to create a class that will be our ‘Request‘ object. The information we send out will be mapped to the variables in our ‘Request‘ class. Then we’ll use this class to run our operation. Request class needs to have a variable for each piece of information you are sending into the system. Below I will attach an example of a ‘Request’ class.
[DataContractAttribute]
class AddSalesOrderHoldRequestContract
{
SalesId salesId;
MCRHoldCode holdCode;
/// <summary>
/// Sales id of the sales order that we should apply the hold code
/// </summary>
/// <param name = "_salesId">SalesId</param>
/// <returns>SalesId</returns>
[DataMemberAttribute]
public SalesId parmSalesId(SalesId _salesId = salesId)
{
salesId = _salesId;
return salesId;
}
/// <summary>
/// The hold code to apply to the sales order hold
/// </summary>
/// <param name = "_holdCode">MCRHoldCode</param>
/// <returns>MCRHoldCode</returns>
[DataMemberAttribute]
public MCRHoldCode parmHoldCode(MCRHoldCode _holdCode = holdCode)
{
holdCode = _holdCode;
return holdCode;
}
}
Create the ‘Response’ object.
We need to create a class that is our ‘Response‘ object. In our code we are going to set the variables in this class to contain the information we want to be returned to the calling program. D365 will then convert these values into JSON structured data.
The Response class needs to have a variable for each piece of information we would like to send back to the calling program. Below I will attach an example of ‘Response’ class.
[DataContractAttribute]
class AddSalesOrderHoldResponseContract
{
boolean result;
List errors;
/// <summary>
/// Result of the request
/// </summary>
/// <param name = "_result">boolean</param>
/// <returns>boolean</returns>
[DataMemberAttribute]
public boolean parmResult(boolean _result = result)
{
result = _result;
return result;
}
/// <summary>
/// List of error messages that occured during the inbound request
/// </summary>
/// <param name = "_errors">List of error messages</param>
/// <returns>List of error messages</returns>
[DataMemberAttribute]
public List parmErrors(List _errors = errors)
{
errors = _errors;
return errors;
}
}
Create the Service class.
The Service class is the most interesting class when you create a custom service in D365. This class is responsible for fetching values from the Request object, running some process, then writing values on the Response object. In this class we will write code for :
- Reading the information in our request object that are sent from the calling program.
- Run the custom logic.
- Populate the response project with data that we want to send back to the calling program.
Below I will attach an example of Service class.
class AddSalesOrderHoldService
{
public AddSalesOrderHoldResponseContract addHold(AddSalesOrderHoldRequestContract contract)
{
boolean result = true;
List errors = new List(Types::String);
//Read the information from the request object
SalesId salesId = contract.parmSalesId();
MCRHoldCode holdCode = contract.parmHoldCode();
//Run the custom logic
try
{
SalesTable salesTable;
select firstonly salesId, SalesStatus from salesTable
where salesTable.SalesId == salesId;
if(salesTable.RecId != 0)
{
//verify the sales order status
if(salesTable.SalesStatus == SalesStatus::Backorder || salesTable.SalesStatus == SalesStatus::None)
{
}
else
{
//cannot apply hold code to sales order in current status
throw error(strFmt("@label:SalesStatusError", salesTable.SalesId, salesTable.SalesStatus));
}
}
else
{
//sales order dont exist
throw error(strFmt("@label:SalesOrderError", salesId))
}
//verify that the hold code exists
MCRHoldCodeTable holdCodeTable;
select firstonly holdCodeTable
where holdCodeTable.MCRHoldCode == holdCode;
if(holdCodeTable.RecId != 0)
{
//declare new MCRHoldCodeTrans record (apply hold code)
MCRHoldCodeTrans holdCodeTrans;
ttsbegin;
holdCodeTrans.InventRefId = salesTable.SalesId;
holdCodeTrans.MCRHoldCode = holdCodeTable.MCRHoldCode;
if(holdCodeTrans.validateWrite())
{
holdCodeTrans.insert();
}
ttscommit;
}
else
{
//hold code dont exist
throw error(strFmt("@label:HoldCodeError, holdCode"));
}
}
catch
{
result = false;
//store errors
SysInfologEnumerator enumerator;
SysInfologMessageStruct msgStruct;
enumerator = SysInfologEnumerator::newData(infolog.cut());
while(enumerator.moveNext())
{
msgStruct = new SysInfologMessageStruct(enumerator.currentMessage());
errors.addEnd(msgStruct.message());
}
//clear infolog
infolog.clear();
}
//create and populate the response object
AddSalesOrderHoldResponseContract response = new AddSalesOrderHoldResponseContract();
response.parmErrors(errors);
response.parmResult(result);
return response;
}
}
Create the service object.
We need also to create the service object, that will point to the service class that we have created before. The Service object, exposes our Service class and allows it to be called by an another system with the proper authentication. In visual studio we can create a service object and add those properties.
Class | Service class name |
Description | A description of the service function. |
External name | Name of the service |
Now, right click one service node and select ‘New service operation’. In the properties of the Service operation you have to specify the method name that you have used to run the custom logic on your service class. In our example :
method | addHold |
Name | addHld |
Your service will look like this:

Create service group.
Now, we have to create ‘The Service Group’ to add our service. Usually we use service groups to organize similar operations together.
First you new to create a ‘Service group’ object and set Auto deploy properties to Yes. After you have created the service group with right click on the service group node you can add a new service. In the properties you can specify your service name. In our example:
Name | AddSalesOrderHoldService |
Service | AddSalesOrderHoldService |
Your service group will look like this:

After you have finished with building your service you need to call it from Postman. On the next blog we will explain how to do it.
Leave a Reply