NOTE: Whenever I write a Google query to find information about the new AX system, I mention the bad word of those who create the name for the Microsoft products. Therefore, in order not to write many letters, I will use the name of AX7 instead of Dynamics 365 for Finance and Operation.
In this topic we will create a some two servises, which communicate in async mode.
In our case External System it is our AX services which starting in async mode some operations and each of it operation invoke another AX service which create new file locally.
In the new version of AX, the creation of custom services is a very simple operation. All you need to do is create a service group that will automatically be deployed, create a service and add it to the service group. And finally, link your service with the class which will be responsible for the logic of the service.
Let's create two services, one of which will generate a unique text string asynchronously within itself. In addition, the first service accepts two parameters: the number of threads and the size of the delay for each thread, by this we can emulate some complex task.
1 Step:
Create a service group
And set Auto Deploy properties to Yes
2 Step:
Then create some service
Then add services to Service Group and setup properties
Ok. Next is to create a class and mapping our service operation with a method on a class. I have seen a situation when we can mapping only instance method and class, so our class and method do not be static.
3 Step:
Create a class
and then mapping a class with our service
setting service properties
and also setting service operation properties
Final result for the first service
Now you need to create a second service that will accept a text string and write it to a file and save it to disk. I will give only a piece of code, all other operations on class linking with the service are similar to the first service
Then build your solution for deploy services.
If you call the GET request, then in response we will receive the signature of our service, but if you run the POST service request, then it will work according to the logic that is written in it. Also, do not forget that the services deployed in the AX instance, so the request must contain a header with an authorization key.
To run the services, I will use the Fiedler program (https://www.telerik.com/download/fiddler)
Let's try to call our services:
Open the program / Composer / Scratchpad
Then we must generate access token with next request:
Where
Your_Instance_Address - AX7 url
Your_Client_Id - generated client id
Your_Client_Secret - generated secret key for client id
Tenant_Id - generated tenant id
How generate tenant, client and secret ids see there
https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-code
and there
In this topic we will create a some two servises, which communicate in async mode.
In our case External System it is our AX services which starting in async mode some operations and each of it operation invoke another AX service which create new file locally.
In the new version of AX, the creation of custom services is a very simple operation. All you need to do is create a service group that will automatically be deployed, create a service and add it to the service group. And finally, link your service with the class which will be responsible for the logic of the service.
Let's create two services, one of which will generate a unique text string asynchronously within itself. In addition, the first service accepts two parameters: the number of threads and the size of the delay for each thread, by this we can emulate some complex task.
1 Step:
Create a service group
And set Auto Deploy properties to Yes
2 Step:
Then create some service
Then add services to Service Group and setup properties
I create Service Group and add two services:
Ok. Next is to create a class and mapping our service operation with a method on a class. I have seen a situation when we can mapping only instance method and class, so our class and method do not be static.
3 Step:
Create a class
class GenerateUniqueString
{
public str getString(int sleepMS)
{
str data = "Test_Async_data_" + "_" + datetime2Str(DateTimeUtil::getSystemDateTime());
System.Threading.Thread::Sleep(sleepMS);
return data;
}
}
and then mapping a class with our service
setting service properties
Final result for the first service
Now you need to create a second service that will accept a text string and write it to a file and save it to disk. I will give only a piece of code, all other operations on class linking with the service are similar to the first service
class SaveStringToDIsc
{
public str downloadFile(str parameters)
{
TextIo file;
FileName filename = @"C:\Temp\Downloads\file.txt";
FileIoPermission permission;
#File
str result = "";
try
{
permission = new FileIoPermission(filename, #io_write);
permission.assert();
file = new TextIo(filename, #io_write);
if (!file)
{
throw Exception::Error;
}
file.write(parameters);
result = "File was successfully saved";
}
catch(Exception::Error)
{
result = "You do not have access to write the file to the selected folder";
}
CodeAccessPermission::revertAssert();
return result;
}
}
Then build your solution for deploy services.
Now let's talk about how to start the services.
NOTE: In this example, I will use services that return and accept data in format JSON. In more detail on how to work with custom services in a different format can be read in the documentation from the Microsoft https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/data-entities/custom-servicesIf you call the GET request, then in response we will receive the signature of our service, but if you run the POST service request, then it will work according to the logic that is written in it. Also, do not forget that the services deployed in the AX instance, so the request must contain a header with an authorization key.
To run the services, I will use the Fiedler program (https://www.telerik.com/download/fiddler)
Let's try to call our services:
Open the program / Composer / Scratchpad
Then we must generate access token with next request:
------------------------- OAUTH
POST https://login.windows.net/Tenant_Id/oauth2/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: login.windows.net
resource=https%3A%2F%2FYour_Instance_Address&client_id=Your_Client_Id&client_secret=Your_Client_Secret&grant_type=client_credentials
Your_Instance_Address - AX7 url
Your_Client_Id - generated client id
Your_Client_Secret - generated secret key for client id
Tenant_Id - generated tenant id
How generate tenant, client and secret ids see there
https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-code
and there
https://www.netiq.com/communities/cool-solutions/creating-application-client-id-client-secret-microsoft-azure-new-portal/
Also, we have to setting client id in AX7, go to System Administration / Setup / Azure Active Directory applications and add new record with your client id.
I recommending use user which has system administrator role
Ok. Lets run our OAuth request, paste your script to scratchpad, select them and click "Execute" button:
Where
yourtoken - token wich we generated and copy previously
Execute this request and see result:
Perfectly. Our service is working.
Now let's do GET request adn see result
GET requests we can do from the browser, for this you just need to enter the address of our service address line (Example: https://YouInstanceUrl/api/services/TestServiceGroup/TestFirstService/getString)
This will complete the first part. In the second part, we will improve our services so that they can call each other automatically
Also, we have to setting client id in AX7, go to System Administration / Setup / Azure Active Directory applications and add new record with your client id.
I recommending use user which has system administrator role
Ok. Lets run our OAuth request, paste your script to scratchpad, select them and click "Execute" button:
At last, everything is ready to call our service. Let's get started
POST https://YouInstanceUrl/api/services/TestServiceGroup/TestFirstService/getString HTTP/1.1
OData-Version: 4.0
OData-MaxVersion: 4.0
Content-Type: application/json;odata.metadata=minimal
Accept: application/json;odata.metadata=minimal
Accept-Charset: UTF-8
Authorization: Bearer yourtoken
Host: YouInstanceUrl
{
"sleepMS":1000
}
yourtoken - token wich we generated and copy previously
Execute this request and see result:
Now let's do GET request adn see result
GET https://YouInstanceUrl/api/services/TestServiceGroup/TestFirstService/getString HTTP/1.1
OData-Version: 4.0
OData-MaxVersion: 4.0
Accept: application/json;odata.metadata=minimal
Accept-Charset: UTF-8
Authorization: Bearer yourtoken
Host: YouInstanceUrl
GET requests we can do from the browser, for this you just need to enter the address of our service address line (Example: https://YouInstanceUrl/api/services/TestServiceGroup/TestFirstService/getString)
This will complete the first part. In the second part, we will improve our services so that they can call each other automatically
Thanks Dimitriy
ReplyDeleteI planning develop external web apps to access some entity Dynamics 365 Finance and Operations.
Does this tutorial can cover my planning or there are another ways to achieve my integration planning
We are really grateful for your blog post. You will find a lot of approaches after visiting your post. I was exactly searching for. Thanks for such post and please keep it up. Great work. custom research papers
ReplyDelete