Consuming OData data entities of D365F&O using OData connected service in .Net Framework Console Application

Arifh
9 min readAug 14, 2023

--

Hi all,
I have recently consumed OData data entities in .Net Console Application using OData connected service. In this blog, I will show you the steps for successful integration.

So let’s first learn some basics.

What is a Data entity in Dynamics 365 Finance and Operations?
According to Microsoft documentation, A data entity is an abstraction from the physical implementation of database tables.

Entity example:
A consumer wants to access data that is related to a customer object, but this data is currently scattered across multiple normalized tables, such as DirParty, CustTable, LogisticPostalAddress, and LogisticElectronicAddress. Therefore, the process of reading and writing customer data is very tedious. Instead, the following customer entity can be designed to encapsulate the entire underlying physical schema into a single de-normalized view.

Now the question arises what is OData connected service?
According to Microsoft documentation, OData Connected Service is a Visual Studio extension that generates strongly-typed C# and Visual Basic client code for a specified OData service. In simple words think of it as a tool to generate client proxy files for an OData Service which helps us to access the data entities of Dynamics 365 F&O.
Note: It supports Visual Studio 2017 and 2019. For prior versions of Visual Studio, you will need to use the OData Client Code Generator tool.

A detailed documentation on these tools is given in the given below link
https://learn.microsoft.com/en-us/odata/client/code-generation-tool

Now that we have learned the basics, let’s dive into some practical things.
I will break down the process into steps so that it can be easy for you to understand and follow.

  1. Step 1: First, we need to register an App on portal.azure.com

In the Redirect URI section, paste the link of your Finance and Operations cloud-hosted environment URI so that you can access it publicly. You can add your cloud-hosted sandbox environment URI.

Note: The above oneBox URI is just for understanding and here it is used for demo purpose. Plus, you must log in to the Azure portal using the same tenant or credentials or user with which you access your cloud-hosted finance and operations.

Step 2. Now, we need to add the following permissions for the app that we created.
AX.FullAccess, Connector.FullAccess, Odata.FullAccess, CustomService.FullAccess (optional).
Also, grant admin consent as well as shown in step 4 in the image below.

You can also create client secrets as shown below. A little tip, save your secret value somewhere safe and do not share it with an unauthorized person. Your secret value will be disappeared once you refresh the page.

Also, save the application (client) and tenant id shown in the overview of your Azure app registrations.

Step 3. Now we need to add the application (client) id in Finance and Operations in the Azure active directory application.
Add the application (client) id which we get from the Azure portal above

Now, the work of the visual studio starts. I am using Visual Studio 2019.

Step 4. Create a .Net Framework Library project

Step 5. Now, go to Extensions and then manage Extensions. Install OData-connected service.

Note: For installation, you need to close your visual studio once. The VSIX installer wizard opens for installation.

Step 6. We need to add a connected service to the UilityOData library project. Follow the steps as shown to configure it.

In the address bar, paste the link of your finance and operations cloud-hosted environment URI which you inserted in the Azure portal while registering the app in step 1. Also, add “/data” at the end of your address to point to the Odata data entities of Dynamics 365 F&O.

Click Next and a list of data entities will be shown to you. It will take time depending on the number of data entities. You can select any data entities from the list. For demo purposes, I selected “CustomerGroups” only.

Click Next, and then finish. It will also take some time.
After successful configuration, the OData documentation opens in your any web browser.

The connected service will include the following files. Build the UtilityOData project and you can see a dll file is also created on a successful build as it is a library project.

Step 7. Go to Manage Nuget Package to install the following libraries.
1. Microsoft.IdentityModel.Clients.ActiveDirectory
2. Microsoft.OData.Client (It will be installed with the configuration of the OData connected service so no need to install it separately)

For installation of the Nuget package, right-click on the project and you will see “Manage Nuget Packages”.

Step 8: Create another .Net Framework Library Project.
Create the project in the same solution for simplicity. I name the project as “AuthenticationUtility” as it is a utility for the Authentication of Azure App.

Now, create a class by the name of “ClientConfiguration”. Paste the following code and replace the necessary credentials with yours.

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 = "<YourCloud-hostedEnvrionmentURI>",
UserName = "<YourUserName>",
Password = "<YourPassword>",

ActiveDirectoryResource = "<YourCloud-hostedEnvrionmentURI>",
ActiveDirectoryTenant = "https://login.microsoftonline.com/<YourTenant>.onmicrosoft.com", // You can find your tenat from Azure portal
ActiveDirectoryClientAppId = "<YourApplication(Cliend)ID>",
// Insert here the application secret when authenticate with AAD by the application
ActiveDirectoryClientAppSecret = "<YourClientSecretValue>",

// 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; }
}
}

You can find your tenant from Azure active directory from its overview section. From there, the primary domain is your tenant.

Create another class by the name of “OAuthHelper” and paste the following code.

using AuthenticationUtility;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//using Microsoft.Identity.Client;
namespace AuthenticaitionUtility
{
public class OAuthHelper
{
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)
{
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;

// OAuth through application by application id and application secret.
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
{

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();
}
}
}

You will also need to add Microsoft.IdentityModel.Clients.ActiveDirectory Nuget Package in this library project as you did in the previous one. Build the project and you can see the dll file is also created on a successful build.

Step 9. The final step: Create a .Net Framework Console Application
Write the name of the project as “TestODataClient”.

Now, we need to add the reference of the two library projects that we created before as shown below.

Then click on browse to find the dll files. The below image is for UtilityOData dll.

You can add the ClientConfiguration dll file as well following the same step.

We also need to add Microsoft.OData.Client from the manage Nuget Packages.

Then in the program.cs file of TestODataClient console application, paste the following code.

using AuthenticationUtility;
using Microsoft.Dynamics.DataEntities;
using Microsoft.OData.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AuthenticaitionUtility;

namespace TestODataClient
{
class Program
{
public static string ODataEntityPath = ClientConfiguration.Default.UriString + "data";

static void Main(string[] args)
{

Uri oDataUri = new Uri(ODataEntityPath, UriKind.Absolute);
var context = new Resources(oDataUri);

context.SendingRequest2 += new EventHandler<SendingRequest2EventArgs>(
delegate (object sender, SendingRequest2EventArgs e)
{
//Add true in the parameter of GetAuthenticationHeader if you want to Authenticate with Client Secret
//Add false in the parameter of GetAuthenticationHeader if you want to Authenticate with Client credentials (username, password)
var authenticationHeader = OAuthHelper.GetAuthenticationHeader(true);
e.RequestMessage.SetHeader(OAuthHelper.OAuthHeader, authenticationHeader);
});

//string companyName = "USMF";
//var vendors = context.Vendors.AddQueryOption("$filter", string.Format("dataAreaId eq '{0}'&cross-company=true", companyName)).Execute();
foreach (var customerGroup in context.CustomerGroups)
{
Console.WriteLine(customerGroup.CustomerGroupId);
//Console.WriteLine(customerGroup.Description);
//Console.WriteLine(customerGroup.DataAreaId);
}

Console.WriteLine("Code executed");
Console.ReadLine();
}
}
}

P.S. To authenticate using client secret value you need to allow the public client flows from Azure app registration as shown below.

Build and run the console App.

Output:
I have hidden a few information due to privacy issues.

Conclusion:
This article explains how we can easily consume OData data entities of Dynamics 365 F&O in .Net Framework Console Application using an OData-connected service.
I tried my best to simplify and clarify the overall steps. Hope it helps everyone trying to do integration between Dynamics 365F&O and .Net Framework using OData entities.

References:

  1. https://github.com/microsoft/Dynamics-AX-Integration
  2. https://devblogs.microsoft.com/odata/tutorial-sample-how-to-use-odata-client-code-generator-to-generate-client-side-proxy-class/
  3. https://learn.microsoft.com/en-us/odata/client/code-generation-tool

Contact Email: arif8h@gmail.com / arif8h@outlook.com

--

--