Development of JSON-based Custom Service for Microsoft Dynamics 365 F&O
In this article we’ll go over on how to develop an integration between Microsoft Dynamics 365 F&O and third-party services using JSON-based…
Development of JSON-based Custom Service for Microsoft Dynamics 365 F&O

In this article we’ll go over on how to develop an integration between Microsoft Dynamics 365 F&O and third-party services using JSON-based custom service. And test it using Postman.
Prerequisites:
- Admin access to a MS D365 F&O development environment.
- Admin access to MS D365 F&O application on development environment.
- Review and complete the process from the article Add New External Application in Microsoft Dynamics 365 F&O.
- Postman (Desktop Or Online).
Process:
- Setup Visual Studio for Microsoft Dynamics 365 F&O Development.
- Development of X++ Custom Service.
- API Testing using Postman for Microsoft Dynamics 365 F&O JSON-based Custom Service.
Step 1: Setup Visual Studio for Microsoft Dynamics 365 F&O Development.
Review and complete the process from the article: Setup Visual Studio for Microsoft Dynamics 365 F&O Development.
Step 2: Development of X++ Custom Service.
- Create a Class with the Name “CSRequest”.
In the Solution Explorer, Right click on the Project.
Select Add > New item.

Under FinanceOperations > Dynamics 365 Items > Code > Class.
Enter the Name, then click on Add.

- Copy and then paste the following code in the Class “CSRequest”.
After paste. Click on Save. Or press Ctrl + S.
[DataContractAttribute]
class CSRequest
{
// Variables used in request body
private str dataAreaId;
private str data;
// For storing dataAreaId value from request body
[DataMember("dataAreaId")]
public str parmDataAreaId(str _value = dataAreaId)
{
if (!prmIsDefault(_value))
{
dataAreaId = _value;
}
return dataAreaId;
}
// For storing Data value from request body
[DataMember("Data")]
public str parmData(str _value = data)
{
if (!prmIsDefault(_value))
{
data = _value;
}
return data;
}
}

- Create a Class with the Name “CSResponse”. (Refer to Step 2 point 1)
Copy and then paste the following code in the Class “CSResponse”.
After paste. Click on Save. Or press Ctrl + S.
[DataContractAttribute]
class CSResponse
{
// Variable used in response body
private boolean success;
private str errorMessage;
private str data;
// For storing Success status value for response body
[DataMember("Success")]
public Boolean parmSuccess(Boolean _value = success)
{
if (!prmIsDefault(_value))
{
success = _value;
}
return success;
}
// For storing ErrorMessage value for response body
[DataMember("ErrorMessage")]
public str parmErrorMessage(str _value = errorMessage)
{
if (!prmIsDefault(_value))
{
errorMessage = _value;
}
return errorMessage;
}
// For storing Data value for response body
[DataMember("Data")]
public str parmData(str _value = data)
{
if (!prmIsDefault(_value))
{
data = _value;
}
return data;
}
}

- Create a Class with the Name “CSEngine”. (Refer to Step 2 point 1)
Copy and then paste the following code in the Class “CSEngine”.
After paste. Click on Save. Or press Ctrl + S.
public class CSEngine
{
// Global variables used for error handling
str errorMsg;
int infologStartLine;
// Entry point for the custom service method getData
public CSResponse getData(CSRequest _request)
{
// Validating request body data
str isValidMsg = this.validateRequestGetData(_request);
// Evaluating request is valid
if (isValidMsg == 'true')
{
// Processing the request
return this.processRequestGetData(_request);
}
else
{
// Returning response for invalid data in request body
return this.createResponse(false, isValidMsg, '');
}
}
// Methond to generate response body
private CSResponse createResponse(boolean _success, str _errorMessage, str _data)
{
var response = new CSResponse();
response.parmSuccess(_success);
response.parmErrorMessage(_errorMessage);
response.parmData(_data);
return response;
}
// Method for obtaining error message
private str getInfologStr(int _infologStartLine)
{
SysInfologEnumerator enumerator;
SysInfologMessageStruct msgStruct;
str error;
container infologData;
int infologCurrentLine = infologLine();
if (infologCurrentLine > _infologStartLine)
{
infologData = infolog.copy(_infologStartLine + 1, infologCurrentLine);
}
if (infologData)
{
enumerator = SysInfologEnumerator::newData(infologData);
while (enumerator.moveNext())
{
msgStruct = new SysInfologMessageStruct(enumerator.currentMessage());
error = strfmt("@SYS324543", error, msgStruct.message());
}
}
return error;
}
// Method for adding error message to the global variable
private void addErrorMsg(str _errorMsg)
{
errorMsg += _errorMsg;
}
// Method for validating the request body data
private str validateRequestGetData(CSRequest _request)
{
str isValid;
DataAreaId dataAreaId;
str data;
dataAreaId = _request.parmDataAreaId();
data = _request.parmData();
isValid = 'true';
if (!CompanyInfo::findDataArea(dataAreaId))
{
return 'dataAreaId does not exist.';
}
if (data == '')
{
return 'No data in the request body.';
}
return isValid;
}
// Method for executing custom logic for the request getData
private CSResponse processRequestGetData(CSRequest _request)
{
str responseData;
responseData = '';
// Setting the infolog scope to capture Error message for the current operation only
infologStartLine = infologLine();
try
{
// For executing company specific logic
changecompany(_request.parmDataAreaId())
{
// For creating the JSON response body
responseData = this.generateJSONResponseForGetData(_request);
}
}
// Exception handling for CLRError
catch (Exception::CLRError)
{
System.Exception exception = CLRInterop::getLastException();
return this.createResponse(false, exception.Message, '');
}
// Exception handling for Error
catch (Exception::Error)
{
this.addErrorMsg(this.getInfologStr(infologStartLine));
return this.createResponse(false, errorMsg, '');
}
// Success state of the operation getData and returning the response
return this.createResponse(true, '', responseData);
}
// Method for generating the JSON response data for the request getData
private str generateJSONResponseForGetData(CSRequest _request)
{
str jsonString;
System.IO.StringWriter stringWriter;
Newtonsoft.Json.JsonTextWriter jsonWriter;
stringWriter = new System.IO.StringWriter();
jsonWriter = new Newtonsoft.Json.JsonTextWriter(stringWriter);
jsonString = '';
jsonWriter.WriteStartObject();
jsonWriter.WritePropertyName("JSONArray");
jsonWriter.WriteStartArray();
for (int i = 0; i < 2; i++)
{
jsonWriter.WriteStartObject();
jsonWriter.WritePropertyName("dataAreaId");
jsonWriter.WriteValue(curExt());
jsonWriter.WritePropertyName("Data");
jsonWriter.WriteValue(_request.parmData());
jsonWriter.WriteEndObject();
}
jsonWriter.WriteEndArray();
jsonWriter.WriteEndObject();
jsonString = stringWriter.ToString();
jsonString = FormJsonSerializer::serializePrimitive(jsonString);
return jsonString;
}
}

- Create a Service with the Name “CustomService”.
Right click on the Project.
Select Add > New item.
Under FinanceOperations > Dynamics 365 Items > Services > Service.
Enter the Name, then click on Add.

- Adding the service Class.
Open the Service “CustomService”.
In the designer, select the “CustomService”.
Right click on it, to open the Properties. Or Press Alt + Enter.
In the property Class, enter/select “CSEngine”.
In the property External Name, enter “CustomService”.
Right click on Service Operations, and select New Service Operation.
Select the new service operation ServiceOperation1.
Right click on it, and select the Properties. Or Press Alt + Enter.

- Adding the entry point for the service operation.
In the property Method, enter/select “getData”.
In the property Name, enter “getData”.
Click on Save. Or press Ctrl + S.

- Create a Service Group with the Name “CSGroup”.
Right click on the Project.
Select Add > New item.
Under FinanceOperations > Dynamics 365 Items > Services > Service Group.
Enter the Name, then click on Add.

- Adding the Service “CustomService” to the Service Group.
Open the Service Group “CSGroup”.
In the designer, select the “CSGroup”.
Right click on it, and select New Service.
Right click on the newly created Service Group Service, and select to open the Properties. Or Press Alt + Enter.
In the property Name, enter/select “CustomService”.
In the property Service, enter “CustomService”.
Click on Save. Or press Ctrl + S.

- Build the Project.
In the Solution Explorer, right click on the Project, and select Build.
After Build completes successfully, Synchronize the Project with database.

Step 3: API Testing using Postman for Microsoft Dynamics 365 F&O JSON-based Custom Service.
Review and complete the process from the article: API Testing Using Postman for Microsoft Dynamics 365 F&O JSON-based Custom Service.
Conclusion:
We successfully developed a new JSON-based custom service and tested it using Postman.
References:
Microsoft article: https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/data-entities/custom-services
메타데이터
- post_id
- f2c8ff9b1099
- slug
- development-of-json-based-custom-service-for-microsoft-dynamics-365-f-o-f2c8ff9b1099
- url
- https://medium.com/@samikhalid22/development-of-json-based-custom-service-for-microsoft-dynamics-365-f-o-f2c8ff9b1099
- canonical_url
- https://medium.com/@samikhalid22/development-of-json-based-custom-service-for-microsoft-dynamics-365-f-o-f2c8ff9b1099
- author_url
- https://medium.com/@samikhalid22
- status
- ok
- fetched_at
- 2026-07-22 16:12:32