Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

Custom Service Integration with D365 FO

Using customsServices is the most flexible and customizable way to integrate with D365FO. Custom services are created with standard D365FO X++ code and can be used for both data-based, and operation-based integrations.

In this blog, I have covered the steps to retrieve customers from D365 FO to the third-party applications. There are three parts specified below to execute the required:

  1. Create Custom Service on D365 FO
  2. Register the application on Azure Portal and add the same in D365 FO
  3. Access the service in third-party application

1. Create Custom Service on D365 FO

Below are the steps to create the custom service in D365 FO.

Create Dynamics Model and Project in visual studio

Create Service class

Add class “IntegrationServiceClass” with method below:

Method returning static Value:

public str getTest()
{
return "Custom Service has been called Successfully.";
}

Method returning customer Detail:
public str getCustomer(str strDataAreaId, str strAccountNum)
{
    CustTable custTable;
    changecompany(strDataAreaId)
    {
        select * from custTable where custTable.AccountNum == strAccountNum;
    }
    return custTable.AccountNum + " - " + custTable.name();
}

Create Service

Right click on solution explorer and add a service named “IntegrationServices”. Set Properties as shown in the screen below:

Right click on Service Operations and add New Service Operations for the methods created in Service class.

Set Name and Method for the created service operations.

Create Service Group

Add the Service Group named “IntegrationServicesGroup” and add a new service named “IntegrationServices”. Set Auto Deploy to “Yes.”

Build the project.

If you get an error such as the one specified in the screen below, update the model and add the “Directory” package. to solve the error of “Dynamics.AX.Directory”.

Update your model and add “ContactPerson” Package to solve the error of “Dynamics.AX.ContactPerson”.

Build the project. On building the project, service will be automatically deployed.

2. Verify service on D365 FO URL

Service URL Format: https:///api/services///

In my case, below will be the service URL

https://usnconeboxax1aos.cloud.onebox.dynamics.com/api/services/IntegrationServicesGroup/IntegrationServices/getTest

https://usnconeboxax1aos.cloud.onebox.dynamics.com/api/services/IntegrationServicesGroup/IntegrationServices/getCustomer

3. Register the application on Azure Portal and add the same in D365 FO

Here are the steps to register the Application on Azure Portal and add that application on D365 FO.

New Registration

Login on https://portal.azure.com/ using your credentials. Select Azure Active Directory >> App Registration.

Click on “New Registration”. Enter details as shown in the screen below and register the application. Select Redirect URL to Web to authorize the application using client Id and secret. In case of selecting Native, the application will be authorized with the user credentials.

Generate Secret Key

To create a secret key, select certificates & secrets. Click on New client secret.

Enter details as shown in the screen below and Add the client secret.

Copy the client secret value

Secret key value:

This value will not be visible again so do not miss to copy this.

API Permissions

To add permissions, click on API Permissions >> Add a permission

Add a permission >> Microsoft APIs >> Dynamics ERP.

Permission will be added as shown in the screen below.

Add Application in Dynamics AX FO

System Administration >> Azure Active Directory applications >> New

Enter Azure application client id in Application Id, application name and user id.

4. Access the service in third-party application

We will access the developed service in the .net application. Before developing the .net application, we will have to create the Authentication application for the security purpose.

AuthenticationUtility Application

Create a .net application for AuthenticationUtility. Add two classes “ClientConfiguration.cs” and “OAuthHelper.cs”.

You can copy the code in these two classes from Microsoft Dynamics AX Integration GitHub repository.

Below is the code of clientConfiguration, I have updated for my Integration Services.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AuthenticationUtility
{
    public partial class ClientConfiguration
    {
        public static ClientConfiguration Default { get { return ClientConfiguration.OneBox; } }
        public static ClientConfiguration OneBox = new ClientConfiguration()
        {
            // You only need to populate this section if you are logging on via a native app. For Service to Service scenarios in which you e.g. use a service principal you don't need that.
            UriString = "https://usnconeboxax1aos.cloud.onebox.dynamics.com/",
            UserName = "[email protected]",
            // Insert the correct password here for the actual test.
            Password = "",
            // You need this only if you logon via service principal using a client secret. See: https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/data-entities/services-home-page to get more data on how to populate those fields.
            // You can find that under AAD in the azure portal
            ActiveDirectoryResource = "https://usnconeboxax1aos.cloud.onebox.dynamics.com", // Don't have a trailing "/". Note: Some of the sample code handles that issue.
            // You can find the TenantID from the application registered on Azure Portal
            ActiveDirectoryTenant = "https://login.microsoftonline.com/<TenantId>", // Some samples: https://login.windows.net/yourtenant.onmicrosoft.com, https://login.windows.net/microsoft.com
            ActiveDirectoryClientAppId = "<clientid>",
            // Insert here the application secret when authenticate with AAD by the application
            ActiveDirectoryClientAppSecret = "<secretkey>",
            // Change TLS version of HTTP request from the client here
            // Ex: TLSVersion = "1.2"
            // Leave it empty if want to use the default version
            TLSVersion = "",
        };
        public string TLSVersion { get; set; }
        public string UriString { get; set; }
        public string UserName { get; set; }
        public string Password { get; set; }
        public string ActiveDirectoryResource { get; set; }
        public String ActiveDirectoryTenant { get; set; }
        public String ActiveDirectoryClientAppId { get; set; }
        public string ActiveDirectoryClientAppSecret { get; set; }
}

}

Add “OAuthHelper.cs” class.

Before adding this class add directory for Microsoft.IdentityModel.Clients.ActiveDirectory from Tools >> NuGet Package Manager >> Package Manager Console with below command.

Install-Package Microsoft.IdentityModel.Clients.ActiveDirectory -Version 5.2.8

Add OAuthHelper code as below and build the application.

using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AuthenticationUtility
{
    public class OAuthHelper
    {
        /// <summary>
        /// The header to use for OAuth authentication.
        /// </summary>
        public const string OAuthHeader = "Authorization";
        /// <summary>
        /// Retrieves an authentication header from the service.
        /// </summary>
        /// <returns>The authentication header for the Web API call.</returns>
        public static string GetAuthenticationHeader(bool useWebAppAuthentication = false)
        {
            string aadTenant = ClientConfiguration.Default.ActiveDirectoryTenant;
            string aadClientAppId = ClientConfiguration.Default.ActiveDirectoryClientAppId;
            string aadClientAppSecret = ClientConfiguration.Default.ActiveDirectoryClientAppSecret;
            string aadResource = ClientConfiguration.Default.ActiveDirectoryResource;
            AuthenticationContext authenticationContext = new AuthenticationContext(aadTenant, false);
            AuthenticationResult authenticationResult;
            if (useWebAppAuthentication)
            {
                if (string.IsNullOrEmpty(aadClientAppSecret))
                {
                    Console.WriteLine("Please fill AAD application secret in ClientConfiguration if you choose authentication by the application.");
                    throw new Exception("Failed OAuth by empty application secret.");
                }
                try
                {
                    // OAuth through application by application id and application secret.
                    var creadential = new ClientCredential(aadClientAppId, aadClientAppSecret);
                    authenticationResult = authenticationContext.AcquireTokenAsync(aadResource, creadential).Result;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(string.Format("Failed to authenticate with AAD by application with exception {0} and the stack trace {1}", ex.ToString(), ex.StackTrace));
                    throw new Exception("Failed to authenticate with AAD by application.");
                }
            }
            else
            {
                // OAuth through username and password.
                string username = ClientConfiguration.Default.UserName;
                string password = ClientConfiguration.Default.Password;
                if (string.IsNullOrEmpty(password))
                {
                    Console.WriteLine("Please fill user password in ClientConfiguration if you choose authentication by the credential.");
                    throw new Exception("Failed OAuth by empty password.");
                }
                try
                {
                    // Get token object
                    var userCredential = new UserPasswordCredential(username, password); ;
                    authenticationResult = authenticationContext.AcquireTokenAsync(aadResource, aadClientAppId, userCredential).Result;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(string.Format("Failed to authenticate with AAD by the credential with exception {0} and the stack trace {1}", ex.ToString(), ex.StackTrace));
                    throw new Exception("Failed to authenticate with AAD by the credential.");
                }
            }
            // Create and get JWT token
            return authenticationResult.CreateAuthorizationHeader();
        }
    }
}

Third Party Application

Create a new .net application “dev_ConsumeIntegrationServices”. Add reference to AuthenticationUtility.dll in this application.

Add Web Form with TextBox and Button to access service of AX as shown below:

Before applying the code, add references shown below:

Microsoft.VisualStudio.QualityTools.UnitTestFramework

To use Newtonsoft.Json library, install package Install-Package Newtonsoft.Json -Version 12.0.3 from Tools >> NuGet Package Manager >> Package Manager Console

Below is the code to access services of AX in the .net application:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using AuthenticationUtility;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
//using SoapUtility.UserSessionServiceReference;
using System;
using System.Text;
using System.IO;
using System.Net;

namespace dev_ConsumeIntegrationServices
{
    public partial class IntegrationForm : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        #region Method - without Parameters
        protected void btnGetTest_Click(object sender, EventArgs e)
        {
            string GetTest = ClientConfiguration.Default.UriString + "api/services/IntegrationServicesGroup/IntegrationServices/getTest";
            var request = HttpWebRequest.Create(GetTest);

            request.Headers[OAuthHelper.OAuthHeader] = OAuthHelper.GetAuthenticationHeader(true);
            request.Method = "POST";
            request.ContentLength = 0;
            using (var response = (HttpWebResponse)request.GetResponse())
            {
                using (Stream responseStream = response.GetResponseStream())
                {
                    using (StreamReader streamReader = new StreamReader(responseStream))
                    {
                        string responseString = streamReader.ReadToEnd();
                        Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
                        Assert.IsFalse(string.IsNullOrEmpty(responseString));
                        //Console.WriteLine(responseString);
                        TextBox1.Text = responseString;
                    }
                }
            }


        }
#endregion

        #region Get Customer - Method with Parameters
        protected void btnGetCustomer_Click(object sender, EventArgs e)
        {
            string getCustomer = ClientConfiguration.Default.UriString + "api/services/IntegrationServicesGroup/IntegrationServices/getCustomer";
            var request = HttpWebRequest.Create(getCustomer);
            request.Headers[OAuthHelper.OAuthHeader] = OAuthHelper.GetAuthenticationHeader(true);
            request.Method = "POST";

            // Pass parameters in JsonSerialize Object start
            var requestContract = new
            {
                strDataAreaId = "USMF",
                strAccountNum = "DE-001"
            };
            var requestContractString = JsonConvert.SerializeObject(requestContract);
            using (var stream = request.GetRequestStream())
            {
                using (var writer = new StreamWriter(stream))
                {
                    writer.Write(requestContractString);
                }
            }
            // Pass parameters in JsonSerialize Object end

            using (var response = (HttpWebResponse)request.GetResponse())
            {
                using (Stream responseStream = response.GetResponseStream())
                {
                    using (StreamReader streamReader = new StreamReader(responseStream))
                    {
                        string responseString = streamReader.ReadToEnd();
                        Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
                        Assert.IsFalse(string.IsNullOrEmpty(responseString));
                        TextBox2.Text = responseString;
                        //Console.WriteLine(responseString);
                    }
                }
            }


        }
    }
    #endregion
}

Wrapping Up

What do you think? The d365 f&o integration was quite simple, right? With a bit of an understanding and a planned approach, we could ace any technical concept easily. Implement this and meanwhile, wait for our next resourceful tutorials on dynamics 365 finance and operations.

The post Custom Service Integration with D365 FO appeared first on DEV IT Journal.



This post first appeared on DEV IT Journal - Simplifying IT, Empowering Busine, please read the originial post: here

Share the post

Custom Service Integration with D365 FO

×

Subscribe to Dev It Journal - Simplifying It, Empowering Busine

Get updates delivered right to your inbox!

Thank you for your subscription

×