Study guide

13.2 Custom Services & SOAP/REST Endpoints

Microsoft Dynamics 365: Finance and Operations Apps Developer Associate MB-500

Track your progress as you read

Finished sections get a check mark.

1 Chapter 1: Cloud & Ecosystem Architecture

1.1 Cloud vs On-Premises Architecture & Deployment Typologies 1.2 Microsoft Ecosystem Integration & Extensibility Boundaries 1.3 Lifecycle Services (LCS) & Implementation Portal

2 Chapter 2: ALM, Environments & Unified Developer Experience

2.1 Package Deployment & Servicing 2.2 Unified Developer Experience (UDE) & Power Platform Admin Center 2.3 Environment Management & Governance

3 Chapter 3: Visual Studio Development & Metadata

3.1 Visual Studio Extension Models & Packages 3.2 Application Explorer & Element Designers 3.3 Database Synchronization & Visual Studio Debugging

4 Chapter 4: Azure DevOps Version Control & CI/CD

4.1 Version Control Architecture: TFVC vs Git in F&O 4.2 Branching, Merging & Conflict Resolution 4.3 CI/CD Build Pipelines & Artifact Generation

5 Chapter 5: UI Elements: Forms, Menus & Labels

5.1 Form Design & Form Patterns 5.2 Menus, Menu Items & Navigation 5.3 Label Files & Localization

6 Chapter 6: Data Model: Tables & Relational Design

6.1 Table Design & Extension 6.2 Views, Queries & Maps 6.3 Data Entity Design & Modeling

7 Chapter 7: Classes, Attributes & AOT Modifiers

7.1 Class Architecture & Access Modifiers 7.2 Attributes & Reflection 7.3 Event Handlers & Pre/Post Method Events

8 Chapter 8: X++ Core Programming & CRUD Operations

8.1 X++ Syntax, Control Flow & Global Functions 8.2 Data Manipulation & CRUD Logic 8.3 Best Practice Rules & Compiler Diagnostics

9 Chapter 9: Advanced OOP, Chain of Command & Extensibility

9.1 OOP Principles & QueryBuilder Class 9.2 Chain of Command (CoC) Implementation 9.3 Extensibility Patterns & Non-Breaking Changes 9.4 Event Handler Classes & Delegate Architecture 9.5 Variable Scoping, Declaration Placement & Object Lifetime

10 Chapter 10: F&O Frameworks & SysTest Unit Testing

10.1 SysOperation Framework Architecture 10.2 Workflow Framework & SysExtensionSerializer 10.3 SysTest Framework & Test Explorer

11 Chapter 11: Reporting Architecture & SSRS Reports

11.1 Reporting Architecture & Datastores 11.2 Report Data Providers & Contracts 11.3 SSRS Report Design, Deployment & Security 11.4 Determining When to Use a Specific Reporting Tool or Platform

12 Chapter 12: Business Intelligence, Workspaces & Electronic Reporting

12.1 Electronic Reporting (ER) Framework 12.2 Power BI Integration & Analytical Workspaces 12.3 Workspaces, Tiles, Lists & KPIs 12.4 Excel Integration & Office App

13 Chapter 13: Integration Patterns & Service Endpoints

13.1 Integration Pattern Evaluation & API Selection 13.2 Custom Services & SOAP/REST Endpoints 13.3 Consuming External Services & REST/SOAP APIs

14 Chapter 14: Data Management Framework (DMF) & Batch Processing

14.1 DMF Concepts, Projects & Sequencing 14.2 Entity Change Tracking & Recurring Integrations 14.3 Composite Entities & Batch OData API 14.4 Monitoring Entity Status, Availability & Job Execution

15 Chapter 15: Power Platform, Business Events & Azure Integrations

15.1 Dual-Write & Virtual Entities 15.2 Business Events Framework 15.3 Azure Key Vault Integration & Secure Storage

16 Chapter 16: Role-Based Security & Extensible Data Security

16.1 Role-Based Security Architecture 16.2 Extensible Data Security (XDS) Policies 16.3 Security Enforcement & Best Practices

17 Chapter 17: Performance Optimization & Data Access Patterns

17.1 Table & Form Caching Mechanisms 17.2 Temporary Tables & Set-Based Operations 17.3 Query Tuning, Indexes & Concurrency 17.4 Diagnostics: Trace Parser, Async & Sandbox Frameworks 17.5 Tuning Variable Scope, Buffer Lifetime & Memory Pressure

13.2 Custom Services & SOAP/REST Endpoints

Key Takeaways Explain This Topic AI

Custom Services in Dynamics 365 Finance and Operations consist of three core AOT artifacts: Service Data Contracts ([DataContractAttribute]), a Service Class containing business logic operations decorated with [SysEntryPointAttribute(true)], and a Service Group (AxServiceGroup).

When added to an AOT Service Group with AutoDeploy set to Yes, custom services are automatically provisioned simultaneously as JSON REST endpoints and SOAP XML endpoints without requiring manual IIS or web routing configuration.

REST custom service operations require HTTP POST requests targeting the URL path /api/services/<ServiceGroup>/<Service>/<Operation>; HTTP GET is not supported for custom service operations.

The [SysEntryPointAttribute(true)] attribute enforces underlying role-based security authorization, ensuring the runtime verifies that the calling user possesses security privileges granting access to the service operation.

External daemon applications authenticate using Microsoft Entra ID (Azure AD) OAuth 2.0 Client Credentials grant, and the Application ID must be mapped to a dedicated F&O user account in the 'Microsoft Entra ID applications' form (SysAADClientTable).

Last updated: September 2026

13.2 Custom Services & SOAP/REST Endpoints

Quick Answer: Custom Services in Dynamics 365 Finance and Operations allow developers to expose custom X++ business logic as external web services. A complete custom service requires three AOT components: Data Contracts ( [DataContractAttribute] ) defining request and response schemas, a Service Class containing public operation methods decorated with [SysEntryPointAttribute(true)] , and an AOT Service Group ( AxServiceGroup ) with AutoDeploy = Yes . The AOS automatically deploys dual endpoints: a JSON REST endpoint ( /api/services/<ServiceGroup>/<Service>/<Operation> ) and a SOAP endpoint ( /soap/services/<ServiceGroup>?wsdl ). All REST custom services require HTTP POST . External applications authenticate via Microsoft Entra ID OAuth 2.0 Client Credentials , which must be mapped to an internal User ID and security roles in the Microsoft Entra ID applications ( SysAADClientTable ) form.

1. Anatomy of an X++ Custom Service

While public Data Entities expose tabular relational data for standard CRUD via OData, Custom Services expose procedural business algorithms (RPC style). When an external application needs to execute business actions—such as calculating tax estimates, validating credit scores, or reserving inventory batches—custom services provide a clean, strongly-typed interface. Custom Service Component Architecture

  • ┌─────────────────────────────────────────────────────────────┐
  • │ AOT Service Group │
  • │ • AxServiceGroup: AutoDeploy = Yes │
  • │ • Groups one or more services under a shared route │
  • └──────────────────────────────┬──────────────────────────────┘
  • │ Deploys
  • ▼
  • ┌─────────────────────────────────────────────────────────────┐
  • │ Service Class │
  • │ • Contains public operation methods │
  • │ • Decorated with [SysEntryPointAttribute(true)] │
  • │ • Orchestrates X++ business logic and transactions │
  • └──────────────────────────────┬──────────────────────────────┘
  • │ Takes / Returns
  • ▼
  • ┌─────────────────────────────────────────────────────────────┐
  • │ Data Contract Classes │
  • │ • Request and Response DTOs │
  • │ • Decorated with [DataContractAttribute] │
  • │ • Getter/setter parm methods with [DataMemberAttribute] │
  • └─────────────────────────────────────────────────────────────┘
  • 2. Service Data Contracts: Structure, Attributes & Collections

A Data Contract is an X++ class that defines the data structure (Data Transfer Object / DTO) exchanged between the caller and the service operation. The runtime serialization engine uses data contracts to convert between X++ objects and JSON/XML payloads.

Core Attributes for Data Contracts

[DataContractAttribute] : Applied to the class declaration. Marks the class as a serializable data contract.

[DataMemberAttribute('CustomName')] : Applied to accessor methods ( parm* ). Exposes the method as a property in the serialized payload. Specifying a custom name parameter allows mapping X++ variable names to external camelCase JSON properties.

[AifCollectionTypeAttribute] : Mandatory for collection parameters. When a contract property accepts or returns a collection (e.g., List or Array ), X++ requires this attribute to inform the CLR serializer of the exact underlying item type. Without it, the serialization engine cannot deserialize incoming JSON arrays into concrete contract objects at runtime.

  • Complete Data Contract Implementation Example // 1. Request Contract for calculating shipping estimates
  • [DataContractAttribute]
  • public final class LogisticsShippingRequestContract
  • {
  • private CustAccount customerAccount;
  • private ItemId itemId;
  • private Qty quantity;
  • private List lineItems; // List of LogisticsLineItemContract
  • [DataMemberAttribute('customerAccount')]
  • public CustAccount parmCustomerAccount(CustAccount _customerAccount = customerAccount)
  • {
  • customerAccount = _customerAccount;
  • return customerAccount;
  • }
  • [DataMemberAttribute('itemId')]
  • public ItemId parmItemId(ItemId _itemId = itemId)
  • {
  • itemId = _itemId;
  • return itemId;
  • }
  • [DataMemberAttribute('quantity')]
  • public Qty parmQuantity(Qty _quantity = quantity)
  • {
  • quantity = _quantity;
  • return quantity;
  • }
  • // CRITICAL: AifCollectionTypeAttribute specifies the exact class inside the List
  • [DataMemberAttribute('lineItems'),
  • AifCollectionTypeAttribute('_lineItems', Types::Class, classStr(LogisticsLineItemContract)),
  • AifCollectionTypeAttribute('return', Types::Class, classStr(LogisticsLineItemContract))]
  • public List parmLineItems(List _lineItems = lineItems)
  • {
  • lineItems = _lineItems;
  • return lineItems;
  • }
  • }
  • // 2. Response Contract returned to the external client
  • [DataContractAttribute]
  • public final class LogisticsShippingResponseContract
  • {
  • private boolean isAvailable;
  • private Amount estimatedCost;
  • private str carrierService;
  • [DataMemberAttribute('isAvailable')]
  • public boolean parmIsAvailable(boolean _isAvailable = isAvailable)
  • {
  • isAvailable = _isAvailable;
  • return isAvailable;
  • }
  • [DataMemberAttribute('estimatedCost')]
  • public Amount parmEstimatedCost(Amount _estimatedCost = estimatedCost)
  • {
  • estimatedCost = _estimatedCost;
  • return estimatedCost;
  • }
  • [DataMemberAttribute('carrierService')]
  • public str parmCarrierService(str _carrierService = carrierService)
  • {
  • carrierService = _carrierService;
  • return carrierService;
  • }
  • }
  • 3. The Service Class & SysEntryPointAttribute

The Service Class contains the operational methods that execute business logic. Every public method meant to be exposed as a service endpoint must be decorated with the SysEntryPointAttribute .

Understanding [SysEntryPointAttribute(true)]

The boolean parameter on SysEntryPointAttribute dictates how the AOS handles authorization:

[SysEntryPointAttribute(true)] (Best Practice / Required for Production): The framework performs a strict runtime security authorization check. It verifies that the authenticated calling user has been granted a Security Privilege or Duty that contains access to this specific service operation menu item. If the user lacks permissions, execution is denied with HTTP 403 Forbidden.

[SysEntryPointAttribute(false)] (Security Risk): Bypasses entry point authorization checks. The method executes under the caller's identity without verifying service-level privileges. This should never be used for sensitive or transactional business logic.

  • Complete Service Class Implementation Example public final class LogisticsShippingService
  • {
  • /// <summary>

/// Calculates shipping availability and rate estimate.

  • /// </summary>
  • /// <param name = "_request">The shipping request data contract.</param>
  • /// <returns>A populated shipping response data contract.</returns>
  • [SysEntryPointAttribute(true)]
  • public LogisticsShippingResponseContract calculateShippingRate(LogisticsShippingRequestContract _request)
  • {
  • LogisticsShippingResponseContract response = new LogisticsShippingResponseContract();
  • if (!_request || !_request.parmCustomerAccount())
  • {
  • throw error("@SYS312345"); // Customer account is mandatory
  • }
  • // Invoke internal X++ business logic (e.g., inventory lookup & carrier rating)
  • CustTable custTable = CustTable::find(_request.parmCustomerAccount());
  • if (!custTable)
  • {
  • response.parmIsAvailable(false);
  • return response;
  • }
  • // Calculate pricing logic
  • Amount estimatedShipping = this.computeRateInternal(_request.parmItemId(), _request.parmQuantity());
  • response.parmIsAvailable(true);
  • response.parmEstimatedCost(estimatedShipping);
  • response.parmCarrierService("Standard Ground");
  • return response;
  • }
  • private Amount computeRateInternal(ItemId _item, Qty _qty)
  • {
  • // Internal calculation logic
  • return _qty * 4.50;
  • }
  • }
  • 4. Service Groups & Automatic Endpoint Routing

In Dynamics 365 Finance and Operations, developers do not configure IIS web handlers, routing tables, or .svc files. Deployment is entirely metadata-driven through AOT Service Groups .

Service Group Configuration

In Visual Studio Solution Explorer, right-click your model and select Add > New Item > Services > Service Group (e.g., LogisticsServiceGroup ).

Set the property AutoDeploy = Yes .

Right-click the Service Group node, select New Service , and reference your Service Class (e.g., LogisticsShippingService ).

Save, build the solution, and synchronize database/metadata.

Endpoint URL Structure

Once deployed, the AOS engine automatically creates two distinct endpoints accessible over HTTPS:

1. JSON REST Endpoint

URL Syntax: https://<environment>.operations.dynamics.com/api/services/<ServiceGroup>/<ServiceName>/<OperationName>

Example: https://contoso.operations.dynamics.com/api/services/LogisticsServiceGroup/LogisticsShippingService/calculateShippingRate

HTTP Method Constraint: Must always be HTTP POST . Even if the operation only queries or reads data without altering state, the REST custom service engine rejects HTTP GET requests with 405 Method Not Allowed . The request parameters must be passed in the JSON body: {

  • "_request": {
  • "customerAccount": "US-001",
  • "itemId": "1000",
  • "quantity": 25
  • }
  • }
  • 2. SOAP Endpoint
  • URL Syntax: https://<environment>.operations.dynamics.com/soap/services/<ServiceGroup>?wsdl
  • Example: https://contoso.operations.dynamics.com/soap/services/LogisticsServiceGroup?wsdl

Emits full WSDL XML metadata for consumption by legacy SOAP clients, enterprise service buses (ESB), or .NET WCF proxies.

5. Authentication & Authorization Pipeline (Entra ID & F&O Setup)

Custom services do not support Basic Authentication or anonymous access. All communication requires token-based authentication via Microsoft Entra ID (formerly Azure Active Directory) .

1. Microsoft Entra ID App Registration

To enable an external daemon application or integration middleware to authenticate:

In the Azure Portal, navigate to Microsoft Entra ID > App registrations and click New registration .

Note the Application (Client) ID and Directory (Tenant) ID .

Under Certificates & secrets , generate a new Client Secret (or upload a public certificate).

No redirect URI is required for daemon service-to-service flows.

2. OAuth 2.0 Client Credentials Grant

The external application issues an HTTP POST to the Microsoft Entra ID token endpoint:

URL: https://login.microsoftonline.com/<TenantId>/oauth2/v2.0/token

Body ( application/x-www-form-urlencoded ):

  • grant_type : client_credentials
  • client_id : <Azure_App_Client_Id>
  • client_secret : <Azure_App_Client_Secret>
  • scope : https://<environment>.operations.dynamics.com/.default

The token service returns an access_token (JWT Bearer token).

3. F&O Registration: SysAADClientTable

An Entra ID token alone is insufficient; D365 F&O must map that token to an internal user identity.

Navigate to System administration > Setup > Microsoft Entra ID applications (table SysAADClientTable ).

Click New and configure:

Client ID: The exact Application (Client) ID registered in Entra ID.

Name: Friendly descriptive name (e.g., ECommerce Logistics Middleware ).

User ID: An active F&O service user account (e.g., SVC_Logistics ).

Important

Why Mapping to an F&O User ID is Mandatory: F&O relies on the assigned internal User ID to evaluate security roles, determine table-level permissions, enforce Extensible Data Security (XDS) policies, identify the default company ( DataAreaId ), and populate database audit fields ( CreatedBy , ModifiedBy ). If the Client ID is not registered in SysAADClientTable , the AOS returns 401 Unauthorized .

4. Role-Based Security Privileges

To satisfy [SysEntryPointAttribute(true)] , developers must grant access to the service operation:

Create a Security Privilege in Visual Studio.

Under the privilege's Permissions > Service Operations node, add the service class operation (e.g., LogisticsShippingService.calculateShippingRate ) and set AccessLevel = Correct .

Add the privilege to a Security Duty , and assign the duty to a Security Role .

Assign the security role to the service account user mapped in SysAADClientTable .

Loading diagram... Custom Service Entra ID Authentication and Execution Pipeline