12 November 2019

How to change the version of the AL Language compiler

Microsoft released a new update to AL Language extension for VS Code. With this new update, the compiler does a few pre-checks before compiling the objects and packages them into a .app file. 

Most probably you will have to do minor changes to your extension codebase to work with the new compiler. Otherwise, you will end up in errors like below:


Waldo already posts a few tweets about this new update. 

If you are not ready to deal with these new warning or error messages, and simply want to compile with using the old version this blog post will help you. 

If you want to go back to a previous version of the AL Language compiler you can use the following method:

But make sure to go back to the latest version and resolve the error as soon as possible, since this is just a workaround.

Please provide your feedback with a comment. 
Thank you and Regards,
Tharanga Chandrasekara
Read more »

24 October 2019

Platform property is still required in app.json

With the Wave 2 release, Microsoft did convert all the C/AL objects into AL. Since they want to lead by example they wanted their own code to be on extensions as well. Plus they wanted to split the objects based on its functionality. After converting to AL, Microsoft put the objects into below two extensions:
  1. System Application
  2. Base Application
If you can remember in the app.json file we had to specify the "platform" and "application" versions to download symbols just like below. 

With the Wave 2 changes, our expectation was that we can simply remove the "platform" and "application" values from the app.json and set the dependency to "System Application" and to "Base Application" extensions. This was completely based on an assumption with "Microsoft completed splitting the objects". 

As soon as we removed the "platform" we get errors on a few tables such as "Date', Integer. It is clear that Microsoft didn't complete on splitting objects into main 2 extensions and there are objects still sitting on the platform. Therefore we had to put back the "platform" into app.json. 


Once you download the symbols you will see 3 AL Packages in your .alpackages folder. 

We will have to keep this till Microsoft completely move tables and functionalities into the main 2 apps.  

Please provide your feedback with a comment. 
Thank you and Regards,
Tharanga Chandrasekara
Read more »

How to handle breaking changes?

Wagner and I are on our way to Vienna to present at Directions EMEA, and now we got into our second flight after flying over 15000Km from Auckland New Zealand, to Dubai. We got another 6 hours to complete on this flight before we step our foot in Vienna. Went through the in-flight entertainment system, but almost all the movies are not my type or watched already. What better way to spend 6 more hours rather writing some blog posts on Wave 2 release. Here we go.

What are these breaking changes?
If there are any schema changes that may result in any data loss, then it can be categorized as a breaking change. Changing the primary key of the table, or changing the data type, reducing the field length can be categorized as breaking changes.



What is the big deal about it as we used to do this all (most) the time?
Exactly! If you are so much used to C/AL then must be wondering is this something even to blog about? Oh yes! Because with the Wave 2 release Microsoft officially stopped shipping C/AL code with the product DVD. Even if you want to run Microsoft Dynamics 365 Business Central on-premise version just because you want to do C/AL changes, you are no longer able to do that with the latest version. This means fob is no longer available and with that force-sync option is gone too.

That is why we need to handle the breaking changes in Microsoft's way. At the start, this whole process will feel like taking to much time, but when you think about it, it is all about giving a better (seamless) experience to the customer.

How do we handle breaking changes?
If your extension is only in sandbox then you are lucky, because you got a couple of easy options.
  1. Drop the sandbox and create a new one. 
  2. In the launch.json file changes the “synchronization” parameter to recreate or force

If the option selected was,

Force: It will force changes regardless of the data loss. This does not guarantee any data loss preventions, it simply applies the changes.

Recreate: It will definitely drop all the tables and table extensions created through the extension. This action will lead to data loss and then create the schema from scratch.

These options are acceptable since it’s the sandbox and you may be comfortable losing data. However above-mentioned options are not available in the production environment.

Then how to handle breaking changes in production?
It all depends on the change you want to make, if the change is related to a field then your option would be to obsolete the field and create a new field on the table, then write an upgrade codeunit to transfer the data from the old field to the new field during the installation.

Dimitri wrote a very nice blog on how to write an upgrade codeunit to transfer data. I might be creating a similar post on that, but I would suggest you read that and get a good understanding of how things work in SaaS.

What if the change is related to the Primary Key of the table?
Unfortunately, you will have to obsolete the entire table and create a new table. Then write an upgrade codeunit to do the data transfer. There are few things to keep in mind when obsoleting a table of a field. Make sure all the table relationships are commented out in the code.

As an example, you create a table and one of the fields has a table relationship to dimension code. Then you went ahead and obsolete your table. It all looks good and works fine if the user did not delete or rename the dimension code.

As soon as a user rename or delete the dimension code system will try to modify all the related fields, and it will throw an error to the user. This seems to be something Microsoft should fix but for time being just to make sure when you obsolete any field or table, remove the table relationship to be on the safe side.

How to make a field or table obsolete?
If you want to obsolete the entire table then you can add Obsolete Status and Reason just like below.

If you want to obsolete the field, then you need to add the status and reason as below.

Once you do that just make sure to handle the data upgrade as well. You need to write a small codeunit to upgrade the data from your old table/field to the new table/field.

What annoys me the most?
There are few things annoys me with this process,
  1. All the obsolete tables and fields still are in the schema which means it will be in the extension code.
  2. Finding a new name: As a developer what I always struggle is to come up with a shorter but good name to a field or to a table. Then have to drop that field or table? That is just sad. 
Is there any solution for this?
As per this moment we don’t, we will have to come up with new names and to maintain all the obsolete fields and tables on our codebase, but the good news is Microsoft knows this and they are working on the solution. They will release function to clean up the schema. 😊 

As per now, just be careful and think twice before releasing any schema changes to the production environment.

Please provide your feedback with a comment.
Thank you and Regards,
Tharanga Chandrasekara
Read more »

09 October 2019

Directions EMEA 2019 : We safely landed in Vienna

We safely landed in Vienna after flying over more than 18000+ Km. This is just normal to most of us who live on the edge of the world. As our prime minister used says even the shortest flight to our neighbor is more than 4 hours away. So flying for more than 24 hours is quite common for most of us.  
Sometimes it feels New Zealand is far away from the rest of the world, but that is the same feeling that holds us tight to the beautiful island nation. This is my first time in Vienna and also to Directions EMEA. Wagner and I presented in the last two Directions ASIA conferences but I’m sure the vibe is totally different in Directions EMEA. 

We will be conducting 3 sessions and all our sessions are focused on integrating Microsoft Dynamics 365 Business Central with the outer world with the help of Azure integration Services. We are planning to take the audience through some of the very interesting Azure technologies that are built to make the integration life easy. 

If you are planning or already working with integration scenarios you might want to book your slot with us. 

Sessions :
“Logic Apps x Microsoft Flow, which one should I choose?" | Date: Wednesday, October 9, 2019 | From: 15:30:00 to 16:15:00 | Room: HALLG1

Unlocking new integration potential for Dynamics 365 BC with Azure Event Grid and Azure Integration | Date: Thursday, October 10, 2019 | From: 11:00:00 to 11:45:00 | Room: HALLG2

Exploring Azure Integration Services - Extending D365 BC with the power of integration | Date: Thursday, October 10, 2019 | From: 16:00:00 to 16:45:00 | Room: HALLG1

Theta: 
This year we got 4 people attending Directions EMEA representing THETA (NZ). Joerg Rau (Head of Theta ERP) is a frequent attendee to Directions EMEA and together with him Carl Head, Wagner Silveira and myself are planning to attend almost all the possible sessions we can, to grasp the latest technologies related to Microsoft Dynamics 365 Business Central. 

The knowledge we gather during the Directions EMEA helps us to add more value and flavor to the solutions we deliver to our customers back home. Even though we are far away from the rest of the world, this keeps us toe to toe with all the other partners in Europe and the US. 

If you see us during the conference(I’m sure you will) don’t be a stranger and just say hi. I would love to get to know you all and who knows the possibilities that might open with just a small “hi”. 

See you tomorrow!
Read more »

14 July 2019

Too many requests reached

What is the maximum number of API requests Microsoft Dynamics 365 Business Central can handle within a one minute? 

Ran into this question a couple of months ago, specifically soon after the April release. Most of our Azure Logic Apps integrations to Microsoft Dynamics 365 Business Central started to fail due to API endpoint changes

Logic Apps were kept on failing every time it tries to push the data into the MSDYN365BC. Initially, the error was related to URI.


1
2
3
4
5
6
{
    "error": {
        "code": "BadRequest_NotFound",
        "message": "The request URI is not valid. Since the segment 'customers' refers to a collection, this must be the last segment in the request URI or it must be followed by an function or action that can be bound to it otherwise all intermediate segments must refer to a single resource."
    }
}

After a while error message changed into "Too many requests reached".

1
2
3
4
5
6
7
{
  "error": {
    "code": "Application_TooManyRequests",
    "message": "Too many requests reached.  Actual (101).  Maximum (100)."

  }
}

So there is a limit! What is the limit and why there is a limit? To get an answer to all these questions we request support from Microsoft. While we wait for an answer from Microsoft we found the answer to our questions from Microsoft Docks: Business Central (Preview)

The document is related to the Business Central Connector and it specifically mentioned that Microsoft Dynamics 365 Business Central can ONLY handle 100 API calls per minute




The limit is enforced mainly to avoid DoS attacks (denial-of-service attack) and to make sure Microsoft Business Central runs smoothly. Too many API requests can bring the product to its knees causing a probable outage.

I suggest you read the "API Limits" article by Microsoft If you are working on the D365 integrations. Even though the article does not directly talk about BC, all the rules discuss it does apply to the BC as well.

Please provide your feedback with a comment. 
Thank you and Regards,
Tharanga Chandrasekara
Read more »

PowerShell: Run Script Error: Exception setting "CursorPosition"

Last week I was working on a PS script to upload files to an FTP and this script supposes to runs through a windows service. It runs perfectly well when it runs manually with the PowerShell ISE.

However, when I scheduled it to run it through a service, service logs below error in the error log. 
Run Script Error: Exception setting "CursorPosition": "A command that prompts the user failed because the host program or the command type does not support user interaction. Try a host program that supports user interaction, such as the Windows PowerShell Console or Windows PowerShell ISE, and remove prompt-related commands from command types that do not support user interaction, such as Windows PowerShell workflows."
While creating the script, I did add CLS to the script to clear the screen, so I can see the execution steps in the output window very clearly. This simple command was causing the error when it runs through the service. Only thing I had to do was simply remove the CLS and restart the service. 

Please provide your feedback with a comment. 
Thank you and Regards,
Tharanga Chandrasekara
Read more »

13 July 2019

How to inject data to Customer Address Line 2 using Microsoft Business Central API

Creating a customer record in Microsoft Dynamics 365 Business Central is a topic I blogged about in one of my previous blog posts. If you have not read them yet I suggest you read it before going through this for better understanding. 

Part 01: Getting Started with Dynamics 365 Business Central APIs
Part 02: Understanding Microsoft Business Central Out-Of-The-Box API Endpoints
Part 03: Understanding Microsoft Business Central Custom API Endpoints

If you want to insert below address to Business Central Customer Card then how would your JSON body look like?


Field Name in BC
Data to inject
Address
 2/34
Address 2
 Coliseum Drive
City
 Albany
County
 Auckland
Country
 NZ
Postal Code
 0632 

First Attempt:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
 "number": "CUST0012",
 "displayName": "Tailspin Toys",
 "type": "Company",
 "email": "jordan.moresby@contoso.com",
 "currencyCode": "NZD",
 "address": {
     "street": "2/34, Coliseum Drive ",
     "city": "Albany",
     "state": "Auckland",
     "countryLetterCode": "NZ",
     "postalCode": "0632"
 }
}

Outcome :

As you can see the first attempt did not work as expected. Address and Address 2 both end up in one field.

Second Attempt :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
 "number": "CUST0012",
 "displayName": "Tailspin Toys",
 "type": "Company",
 "email": "jordan.moresby@contoso.com",
 "currencyCode": "NZD",
 "address": {
     "street": "2/34, \r\nColiseum Drive ",
     "city": "Albany",
     "state": "Auckland",
     "countryLetterCode": "NZ",
     "postalCode": "0632"
 }
}

Outcome:
It did work and the "Address 2" field gets filled with the data we wanted. The change I did was I added \r\n into my JSON body. \r\n is used as a newline character in Windows and this is a very common way to go to a new line. 

 \r\n = CR + LF → Used as a new line character in Windows  

Please provide your feedback with a comment. 
Thank you and Regards,
Tharanga Chandrasekara
Read more »

Understanding Microsoft Business Central Custom API Endpoints

This is the third blog post about the Microsoft Business Central APIs and I suggest you go through below blog posts first if you haven't read them yet.

Part 01: Getting Started with Dynamics 365 Business Central APIs
Part 02: Understanding Microsoft Business Central Out-Of-The-Box API Endpoints

If you want to access custom developed API then this blog post will give you the details of how the API endpoint will be. 

** from this point onwards "https://api.businesscentral.dynamics.com" will be referred to as "{BaseURL}

Tenant version is below 14.1:

{BaseURL}/v1.0/<your tenant domain>/<environment name>/api/<api publisher>/<api group>/<api version>

Tenant version is 14.1 or above:

{BaseURL}/v2.0/<your tenant domain>/<environment name>/api/<api publisher>/<api group>/<api version>

You might be wondering from where the "api publisher", "api group" and "api version" are coming from. These values are defined during the development of the custom API.

Below is a custom developed API page and these values are defined as properties of the page.

Below are the endpoints to access above mentioned custom API.
Tenant version is below 14.1:

{BaseURL}/v1.0/<your tenant domain>/<environment name>/api/tc/iot/beta/companies/<companyID>/outdoortempentries

Tenant version is 14.1 or above:


{BaseURL}/v2.0/<your tenant domain>/<environment name>/api/tc/iot/beta/companies(<companyID>)/outdoortempentries

Please provide your feedback with a comment. 
Thank you and Regards,
Tharanga Chandrasekara
Read more »

Understanding Microsoft Business Central Out-Of-The-Box API Endpoints

If you are working on a project which involves integrating a third party application to Microsoft Dynamics 365 Business Central, then I assume you have already come across with the Business Central APIs. 

I noticed that most of the developers are still not comfortable with the endpoints of the BC APIs. Therefore this blog post is about how to understand the BC API endpoints.

Endpoint contains a couple of sections.

Sections of the URL
Purpose
https://api.businesscentral.dynamics.com
Base URL. This will be the same for all the out-of-the-box APIs and for custom APIs
/v1.0
Version
/your tenant domain
Domain name or ID
/environment name
Environment name. Can get the name from the admin portal. Ex: production, sandbox
/api
This is a keyword
/beta 
The version of the API.

** from this point onwards "https://api.businesscentral.dynamics.com" will be referred to as "{BaseURL}

If you want to use out-of-the-box API then the endpoint would be : 
{BaseURL}/v1.0/<your tenant domain>/<environment name>/api/beta  

Might get an error like below when calling the endpoint even though the correct credentials were provided with the request. 

1
2
3
4
5
6
{
    "error": {
        "code": "Authentication_InvalidCredentials",
        "message": "The server has rejected the client credentials."
    }
}

I encountered this recently and manage to find the reason behind this. Above endpoint will only work if your tenant version is below 14.1. If the tenant version is 14.1 or above then it is a must to use the API version 2.0. (yet to confirm by the Microsoft)

For the tenant which are 14.1 or above endpoint would be:


{BaseURL}/v2.0/<your tenant domain>/<environment name>/api/beta   

Result body will contain all the out-of-the-box APIs for Business Central.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
{
    "value": [
        {
            "name": "items",
            "kind": "EntitySet",
            "url": "items"
        },
        {
            "name": "companies",
            "kind": "EntitySet",
            "url": "companies"
        },
        {
            "name": "customers",
            "kind": "EntitySet",
            "url": "customers"
        }
    ]
}

Before you call any other API it is a must to point the URL to a specific company. In order to do that you can call the below Endpoint
Tenant version is below 14.1:

{BaseURL}/v1.0/<your tenant domain>/<environment name>/api/beta/companies

Tenant version is 14.1 or above:


{BaseURL}/v2.0/<your tenant domain>/<environment name>/api/beta/companies

It will return all the companies available in the tenant. 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
{
    "value": [
        {
            "id": "e3dbe661-9c12-47d0-81f8-1186bd32518ab",
            "systemVersion": "34093",
            "name": "CRONUS NZ",
            "displayName": "CRONUS NZ",
            "businessProfileId": ""
        },
        {
            "id": "e15523c2-b04f-438c-b1bc-756321a91fae",
            "systemVersion": "34093",
            "name": "My Company",
            "displayName": "My Company",
            "businessProfileId": ""
        }
    ]
}

Version 14.1 and above treat segments as collections. Therefore it is a must to use ( ) when specifying a single record in all the new tenant versions. 

Tenant version is below 14.1:

{BaseURL}/v1.0/<your tenant domain>/<environment name>/api/beta/companies/<companyID>

Tenant version is 14.1 or above:

{BaseURL}/v2.0/<your tenant domain>/<environment name>/api/beta/companies(<companyID>)

Once you select the company, you can call the other entities in the same way you call the companies. 

As an example below calls will give you the list of items available. 
Tenant version is below 14.1:
{BaseURL}/v1.0/<your tenant domain>/<environment name>/api/beta/companies/<companyID>/items

Tenant version is 14.1 or above:

{BaseURL}/v2.0/<your tenant domain>/<environment name>/api/beta/companies(<companyID>)/items

If you want to retrieve a single item then below can be used
Tenant version is below 14.1:
{BaseURL}/v1.0/<your tenant domain>/<environment name>/api/beta/companies/<companyID>/items/<itemID>

Tenant version is 14.1 or above:

{BaseURL}/v2.0/<your tenant domain>/<environment name>/api/beta/companies(<companyID>)/items(<itemID)

Good luck and happy integration!

Please provide your feedback with a comment. 
Thank you and Regards,
Tharanga Chandrasekara
Read more »

01 July 2019

Fourth consecutive year as a Microsoft Most Valuable Professional (MVP) - Business Applications

Honored to receive my 4th consecutive MVP award for Business Applications. 

Congratulations to my fellow MVPs and best wishes to those boarding on a new journey. A special shout-out goes to my family, @ThetaNet, @MSDYN365BC, and @freddydk for all the support!


Thank you, everyone, for helping me out on this great journey and planning to do more in this year. 

Thank you and Regards,
Tharanga Chandrasekara
Read more »

05 March 2019

Dynamics 365 Business Central: Permissions required to download AL symbols

Your user needs to have the necessary permission to download AL symbols from Visual Studio Code (VSCode), else you will end up with "Could not download symbols" error in VS Code.

In order to download symbols, User needs to have SUPER permission or should have "D365 EXTENSION MGT" permission assigned. Symbols are stored per tenant and not per company, therefore Company field must be blank in either option.

Clear credentials cache in VSCode and sign in again from VS Code (Download symbols and it will ask your credentials to sign in) 
once you have the "D365 EXTENSION MGT" permission group or SUPER permission set assigned to the user, 
This time VSCode will successfully download symbols from Microsoft Dynamics 365 Business Central.


Please provide your feedback with a comment.
Thank you and Regards,
Tharanga Chandrasekara
Read more »

01 March 2019

How to check Microsoft Dynamics 365 Business Central tenant version

You can use the "System Information" page to check the current version of Microsoft Dynamics 365 Business Central tenant.

Simply search for "System Information" using "Tell me what to do" and click on the "System Information" link in the result. 

"System information" page will show the current version of the tenant. Version get change every time Microsoft upgrade the tenant.

Another way of checking the platform version is by using the admin center. 

Please provide your feedback with a comment. 
Thank you and Regards,
Tharanga Chandrasekara
Read more »

How to access action output in Logic Apps

If you are working on Logic App to integrate Microsoft Dynamics 365 Business Central with any other third party application, by now most probably you must have used HTTP requests or custom connectors (mainly with SOAP web services). 

I saw a couple questions in the forum asking how to access action output in Logic App. 

Below JSON is copied from an action output:
 {  
  "Soap:Envelope": {  
   "@xmlns:Soap": "http://schemas.xmlsoap.org/soap/envelope/",  
   "Soap:Body": {  
    "isPostingPeriodOpen_Result": {  
     "@xmlns": "urn:microsoft-dynamics-schemas/codeunit/GenJnlPost",  
     "return_value": "false"  
    }  
   }  
  }  
 }  

What if you want to read the "return_value" field of the action output? You can use any of the below statements based on your requirement. 
  • Below statement will return the actual value or if the value is empty it will return ''
 {ActionOutputs('Compose_isPostingAllowed')?['Soap:Envelope']?['Soap:Body']?['isPostingPeriodOpen_Result']?['return_value']}   
  • Below statement will return the actual value or if the value is empty it will return null
 ActionOutputs('Compose_isPostingAllowed')['Soap:Envelope']['Soap:Body']['isPostingPeriodOpen_Result']['return_value']  

Please provide your feedback with a comment. 
Thank you and Regards,
Tharanga Chandrasekara
Read more »

28 February 2019

Call a Microsoft Dynamics 365 Business Central function through a Web Service : SOAPAction

Today I did some work with a Logic Apps and one of the requirement was to call a Business Central function through a Web Service. 

I normally use Postman to simulate requests, export the collection and use that to create the Logic App connector. 

Codeunit which I published as a web service had few functions exposed. I wanted to call one of those functions with values passing in and read the return value. 

If I just call (POST) Web Service with the SOAP Envelope (Like below image) it will just return the WDSL. Not the result I was expecting. 

Header :

SOAP Request and Response:

However, SOAP UI return the value I was expecting it to return. 

How that can be possible?  We looked into the "HTTP log" of the SOAP UI, and we saw SOAPAction is defined and its pointing to the function I want to call. 


I did the same thing in Postman and it worked. Below is my request header and you can notice that I add "SOAPAction" to the header. 
If you didn't define the "SOAPAction" in the request header, the result will bring back the WDSL regardless of your SOAP Envelope. 
I use the postman request to create my HTTP request in Logic App. There is a much easy way of doing this in Logic App with the help of custom connector. I will share those details in another day from a new blog post. 

** Thank you Stephen Gichure for helping me to prepare this blog post.

Please provide your feedback with a comment. 
Thank you and Regards,
Tharanga Chandrasekara
Read more »