Creating a Custom JSON Service in D365FO

This guide explains how to create a custom service in Dynamics 365 Finance and Operations (D365FO) that returns a list of customer balances in JSON format. It covers:

  • Request and response data contracts
  • The service class
  • Service group setup
  • Azure AD configuration for secure access


1. Overview

Custom services in D365FO allow you to expose business logic as RESTful endpoints. By using [DataContract] and [DataMember] attributes, D365FO handles JSON serialization/deserialization automatically.

In this example I'll expose a service to get a customer's balance and phone number for a specific customer group from a legal entity.


2. Request Data Contract

Defines the input parameters for the service: company and customer group.

[DataContract]
final class SIMIntegrationCustomerBalanceInfoRequest
{
    private DataAreaId dataAreaId;
    private CustGroupId custGroupId;

    [DataMember("Company")]
    public str parmDataAreaId(str _value = dataAreaId)
    {
        if (!prmIsDefault(_value)) dataAreaId = _value;
        return dataAreaId;
    }

    [DataMember("CustomerGroup")]
    public str parmCustGroupId(str _value = custGroupId)
    {
        if (!prmIsDefault(_value)) custGroupId = _value;
        return custGroupId;
    }
}
        

3. Response Data Contract

Defines the structure of the customer record returned by the service.

[DataContract]
final class SIMIntegrationCustomerBalanceInfoResponse
{
    CustAccount customerAccount;
    Name customerName;
    AmountMST balance;
    Phone phone;

    [DataMember("CustomerAccount")]
    public str parmCustomerAccount(str _customerAccount = customerAccount)
    {
        customerAccount = _customerAccount;
        return customerAccount;
    }

    [DataMember("CustomerName")]
    public str parmCustomerName(str _customerName = customerName)
    {
        customerName = _customerName;
        return customerName;
    }

    [DataMember("Balance")]
    public real parmBalance(real _balance = balance)
    {
        balance = _balance;
        return balance;
    }

    [DataMember("Phone")]
    public phone parmPhone(phone _phone = phone)
    {
        phone = _phone;
        return phone;
    }
}
        

4. Response List Contract

Wraps the response list for proper JSON serialization.

[DataContract]
final class SIMIntegrationCustomerBalanceInfoResponseList
{
    List customerBalances;

    [DataMember("customerBalances"),
     AifCollectionType("_customerBalances", Types::Class, classStr(SIMIntegrationCustomerBalanceInfoResponse)),
     AifCollectionType("return", Types::Class, classStr(SIMIntegrationCustomerBalanceInfoResponse))]
    public List parmCustomerBalances(List _customerBalances = customerBalances)
    {
        customerBalances = _customerBalances;
        return customerBalances;
    }
}
        

5. Service Class

Contains business logic to retrieve customer balances.

final class SIMIntegrationCustomerBalanceInfoResponseService
{
    public SIMIntegrationCustomerBalanceInfoResponseList getCustomersBalances(SIMIntegrationCustomerBalanceInfoRequest _request)
    {
        SIMIntegrationCustomerBalanceInfoResponseList response = new SIMIntegrationCustomerBalanceInfoResponseList();
        List customerBalances = new List(Types::Class);
        CustTable customer;

        changecompany(_request.parmDataAreaId())
        {
            while select customer
                where customer.CustGroup == _request.parmCustGroupId()
            {
                if (customer.phone())
                {
                    SIMIntegrationCustomerBalanceInfoResponse customerBalanceResponse = new SIMIntegrationCustomerBalanceInfoResponse();
                    customerBalanceResponse.parmCustomerAccount(customer.AccountNum);
                    customerBalanceResponse.parmCustomerName(customer.name());
                    customerBalanceResponse.parmPhone(customer.phone());
                    customerBalanceResponse.parmBalance(customer.balanceMST());
                    customerBalances.addEnd(customerBalanceResponse);
                }
            }
            response.parmCustomerBalances(customerBalances);
        }
        return response;
    }
}
        

6. Create Service and Service Group

  1. Create a new service in AOT:
  2. Create a new service group:
  3. Deploy the service group.


7. Microsoft Entra ID applications

To access the service externally:

  1. Go to Azure Portal > Azure Active Directory > App registrations > New registration
  2. Set a name and register
  3. Copy:Application (client) IDDirectory (tenant) ID
  4. Generate a client secret under Certificates & secrets
  5. In D365FO, go to:System administration > Setup > Microsoft Entra ID applications
  6. Add a record with:Client IDUser ID (with service access)


8. Calling the Service

Use an HTTP client like Postman.

  • Method: POST
  • URL:

https://<your-env>.cloudax.dynamics.com/api/services/SIMIntegrationServiceGroup/SIMIntegrationCustomerBalanceService/getCustomersBalances
        

  • Headers:Authorization: Bearer <access_token>Content-Type: application/json
  • Body:

{
  "Company": "USMF",
  "CustomerGroup": "10"
}
        

9. JSON Serialization

D365FO automatically handles JSON serialization for classes decorated with [DataContract] and [DataMember].

The result will be like this:

{
    "$id": "1",
    "customerBalances": [
        {
            "$id": "2",
            "CustomerAccount": "Cust1",
            "CustomerName": "Cust1Name",
            "Balance": 0.0,
            "Phone": "+123456789"
        },
        {
            "$id": "3",
            "CustomerAccount": "Cust2",
            "CustomerName": "Cust2Name",
            "Balance": 399.5,
            "Phone": "123456789"
        }
}        
Sana Hammami

Technical Consultant Microsoft Dynamics 365 Finance & Operations | Power Platform | Microsoft Certified MB-500 | PL-400

1mo

Well done Hatem! Great explanation 👍

Dhia OTHMANI

Microsoft Dynamics 365 F&O Technical Consultant

1mo

My new go-to blog ❤️

To view or add a comment, sign in

Others also viewed

Explore topics