How “Business Central OData V4 Unbound Actions” and “Xamarin” are a perfect match.

THE MOBILE PERSPECTIVE IN QUERY ODATA AND API

I initially found it difficult to implement complex interfaces between Business Central and Xamarin mobile apps by using ODATAv4 and API Pages.

Luckily Busines Central offers plenty of solutions to implement interfaces and both OData Bound and Unbound Actions are really awesome features.

One of common scenario I have to deal with is a mobile app showing sales prices, discounts and availability for a specific item for a customer.

In this situation, I prefer to leave to Business Central the logic to determine the right price and discount for the item because often this evaluation involves a custom logic implemented on BC side and the final price is not obtained as it would be with the standard.

Moreover with BC v16 a new logic and interface for price evaluation has been introduced and the “Sales Price” is now obsolete:

https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-extending-best-price-calculations

STEP 1: THE BUSINESS CENTRAL DATA UNBOUND ACTION

This is the sample codeunit with two different type of parameters.

In the first procedure I pass a generic JSON and then I deserialise it.

In the second procedure I pass direct parameters.

STEP 2: MAP THE CODEUNIT IN WEB SERVICES

The configuration may be managed via WSPublishing.xml.

STEP 3: TEST THE API WITH INSOMNIA

The POST for the two procedures:

The company is passed as an header parameters. May be passed in the URL too but I on my opinion the header solution is easier for Xamarin Forms implementation.

STEP 4: THE XAMARIN HTTP REQUEST

The Json input class:

This is the Business central JSON mapped in the C# class:

The Xamarin Forms Request with the company passed as http header.

REFERENCES

Creating and Interacting with an OData V4 Unbound Action

https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-creating-and-interacting-with-odatav4-unbound-action

Stefano Demiliani Dynamics 365 Business Central: using OData V4 Bound Actions

https://demiliani.com/2019/06/12/dynamics-365-business-central-using-odata-v4-bound-actions/

Codeunit API’s in Business Central

https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-view-table-data

LAST UPDATED

18th of April, 2021

Investigate Business Central API slowdowns and outages by using Telemetry and Azure Application Insights

MONITOR API ON SAAS AND PREMISE ENVIRONMENT

Telemetry is a magic to tool monitor Business Central. It allows to investigate API slowdown reports and claims of users.

Users may have the incorrect perception that SaaS and Premise environments have reliability problems.

Fortunately, Telemetry is a good solution to make it clear whether a tenant is instead stable.

Telemetry allows to have an indisputable tool to monitor HTTP error occurred during API requests (eg: errors 429, 500, 404 and so on).

The final report of this tutorial outputs, for each API requests, all the information needed to investigate slowdown and outages.

These telemetry fields are all it needs to check health and status: http status code, the execution time, the sql rows and executes and the endpoint.

It’s just disappointing the fact only BC16+ (thx Kennie Nybo Pontoppidan corrected my mistake about the version) supports telemetry on Web Services and API, as documented:

https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/administration/telemetry-webservices-access-key-trace

STEP 1: CREATE AZURE APPLICATION INSIGHTS

Log to Azure Portal and create a new “Application Insights”. This operation is just as simple as in pictures.

Please check the “Istrumentation Key” and the “Connection String” values because they are needed when configuring Telemetry on Business Central tenants.

ENABLE TELEMETRY ON BUSINESS CENTRAL SAAS

To enable Telemetry I access the Admin Center of Business Central Saas. The admin center is accessible from this url:

https://businesscentral.dynamics.com/{your_tenant_id}/admin

Then select the environment

And copy the “Application Insights Key” inside the textbox.

ENABLE TELEMETRY ON BUSINESS CENTRAL ON PREMISE

For the On Premise version of Business Central the “Application Insights Instrumentation Key” is configurable from the “Administration Center” panel.

ACCESS TELEMETRY DATA

Azure Portal allows to read and query the data but PowerShell looks like a powerful too.

QUERY TELEMETRY DATA IN AZURE PORTAL

By using Log Analytics and KQL queries directly from the Azure Portal it is possibile to filter to search specific events.

Since the investigation involves HTTP errors occurred during HTTP API request all it is necessary is to query the proper KQL

traces
| where operation_Name == ‘Web Services Call’
and message contains “(Api)”

The output is the list of records of API calls:

By expanding a row we can expand the “customDimensions” tag.

Under customDimensions, finally, is shown the HTTP result:

Since customDimensions is a “dynamic type” the KQL query is a little tricky:

 traces 
| extend httpStatusCode = parsejson(tostring(parsejson(tostring(customDimensions.httpStatusCode))))
| extend serverExecutionTime = parsejson(tostring(parsejson(tostring(customDimensions.serverExecutionTime))))
| extend serverExecutionTime = parsejson(tostring(parsejson(tostring(customDimensions.serverExecutionTime))))
| extend totalTime = parsejson(tostring(parsejson(tostring(customDimensions.totalTime))))
| extend category = parsejson(tostring(parsejson(tostring(customDimensions.category))))
| extend sqlRowsRead = parsejson(tostring(parsejson(tostring(customDimensions.sqlRowsRead))))
| extend sqlExecutes = parsejson(tostring(parsejson(tostring(customDimensions.sqlExecutes))))
| extend endpoint = parsejson(tostring(parsejson(tostring(customDimensions.endpoint))))
| where  operation_Name == 'Web Services Call' 
and message  contains "(Api)"
| project httpStatusCode, serverExecutionTime , totalTime , category , sqlRowsRead , sqlExecutes , endpoint , operation_Name

The final result is just what we need to investigate on HTTP outages:

HOW TO QUERY TELEMETRY DATA WITH POWERSHELL

On the “API Access” blade click the “Create API Key” button. Copy the generated and saved it because it will never ever be accessible again. The “Application ID” will be used to for PowerShell.

I find it easy to test with Insomia. The request is:

GET https://api.applicationinsights.io/v1/apps/{app-id}/query?query=

The query language:

?query=traces | where timestamp > ago(1d)

Here is my PowerShell script:


$key = "{APP_KEY_FROM_AZURE}"
$appId = "{APP_ID_FROM_AZURE}"

$Query=[uri]::EscapeUriString("?query=traces | where timestamp > ago(1d)")

$filename = "{your_path}/{your_file}.kql"
$queryText = Get-Content $filename
$Query=[uri]::EscapeUriString("?query=$queryText")


$headers = @{ "X-Api-Key" = $key; "Content-Type" = "application/json" }

$response = Invoke-WebRequest -uri  "https://api.applicationinsights.io/v1/apps/$appId/query$Query" -Headers $headers -Method Get

$json = ConvertFrom-Json $response.Content

$headerRow = $null
$headerRow = $json.tables.columns | Select-Object name
$columnsCount = $headerRow.Count
$logData = @()
foreach ($row in $json.tables.rows) {
   $data = new-object PSObject
   for ($i = 0; $i -lt $columnsCount; $i++) {
      $data | add-member -membertype NoteProperty -name $headerRow[$i].name -value         $row[$i]
   }
   $logData += $data
   $data = $null
}

$logData

The KQL script file is the same as the previous

 traces 
| extend httpStatusCode = parsejson(tostring(parsejson(tostring(customDimensions.httpStatusCode))))
| extend serverExecutionTime = parsejson(tostring(parsejson(tostring(customDimensions.serverExecutionTime))))
| extend serverExecutionTime = parsejson(tostring(parsejson(tostring(customDimensions.serverExecutionTime))))
| extend totalTime = parsejson(tostring(parsejson(tostring(customDimensions.totalTime))))
| extend category = parsejson(tostring(parsejson(tostring(customDimensions.category))))
| extend sqlRowsRead = parsejson(tostring(parsejson(tostring(customDimensions.sqlRowsRead))))
| extend sqlExecutes = parsejson(tostring(parsejson(tostring(customDimensions.sqlExecutes))))
| extend endpoint = parsejson(tostring(parsejson(tostring(customDimensions.endpoint))))
| where  operation_Name == 'Web Services Call' 
and message  contains "(Api)"
| project httpStatusCode, serverExecutionTime , totalTime , category , sqlRowsRead , sqlExecutes , endpoint , operation_Name
| summarize OpNameCount=count() by tostring(httpStatusCode)

PowerShell allows to create your own logic around all the telemetry data and I find it very useful to give a meaning to telemetry data.

REFERENCES

https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/administration/telemetry-enable-application-insights

“Dynamics 365 Business Central: handling telemetry with Azure Application Insights” and “Using Powershell to retrieve your Dynamics 365 Business Central telemetry” by Stefano Demiliani:

Query REST API:

https://dev.applicationinsights.io/documentation/Using-the-API/Query

KQL Query language reference:

https://docs.microsoft.com/it-it/azure/data-explorer/kql-quick-reference

NEXT ARTICLE

As Microsoft suggested there are either some other powerful tools and ways to monitor and alert.

We added jupyter notebook troubleshooting guides for exactly this scenario. Get it here: https://github.com/microsoft/BCTech/tree/master/samples/AppInsights/TroubleShootingGuides

We also added a lot of KQL samples here: https://github.com/microsoft/BCTech/tree/master/samples/AppInsights/KQL/Queries Keep up the great work uptaking hashtag#msdyn365bc telemetry. Have you considered adding an alert in Azure Monitor? Read more here https://github.com/microsoft/BCTech/tree/master/samples/AppInsights/Alerts (also with a few sample KQL queries for alerts)

LAST UPDATED

17th of March, 2021

“Control Add In” in Business Central: why iframes are not a good idea?

BUSINESS CENTRAL CONTROL ADD IN IFRAMES

Most of Business Central Control AddIns sample I found on the internet mostly uses the <IFRAME> to embed an external webpage or website inside Business Central page.

This solution is pretty common because it allows to easily and quickly embed the page just by using the <iframe> tag.

With the iframe the business central webpage (https://businesscentral.dynamics.com/) just embeds your own webpage (https://www.yoursite.com)

But <iframes> have a major problem. They allow cross site javascript scripting between the parent and the iframe page but they does not allow the scripting on the other direction. This is prevented for security reason, as often happens with iframes.

On the past cross scripting was used to get private information, it was enough just to embed any bank website inside an iframe to access all of its information from the parent page. So, just embedding the login page in an iframe, allowed malicious users to access credentials entered in the login page.

This means that, by using iframes, the browser JavaScript’s engine does not allow cross site scripting.

In my previous article I used in fact a different approach to implement a control addin.

“Control Add In” in Business Central: a responsive web app fully integrated in web client and mobile app:

https://businesscentraldotblog.wordpress.com/2021/02/26/control-add-in-in-business-central-a-responsive-web-app-fully-integrated-in-web-client-and-mobile-app/

With the correct solution I used this piece of code to embed an external static resource on my BC page:

I first included: ‘https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-debug.js&#8217;,

Then I loaded the page with this AJAX function :

$.ajax({ url: url, xhrFields: { withCredentials: true } )).done(function(data) { $(“#controlAddIn).text(data); });

REFERENCES: SOLUTION NOT USING FRAMES

https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-control-addin-object

REFERENCES: SOLUTIONS USING FRAMES

LAST UPDATED

27th of February, 2021

“Control Add In” in Business Central: a responsive web app fully integrated in web client and mobile app.

BUSINESS CENTRAL CONTROL ADD IN

Control AddIns looks like a fantastic solution to integrate a Business Central page with an external responsive Web Application.

The responsive website automatically adapts to the layout thus is fully working both on web client and mobile app for tablets and mobile phones.

The integration is pretty simple, in my scenario I a page includes a control AddIn that embeds a single WEB page. The page exchanges data with a Web Page. The Web Page is responsive and based on a a basic Azure Function.

The control addin allows to easily implement a clean solution that integrates business central pages with external websites.

As shown in figure the business control page implements TRIGGERS, the control addin implements the INTERFACE of the common procedures and events. The WebSite shares those procedures and events with the business central page.

This allow a two ways binding between those two components: the webpage calls the procedures declared in the control add in and implemented in the trigger page.

THE CONTROL ADDIN

The Control AddIn is the most important part of the project and is basically a gateway between the Business Page and the WebSite.

Inside the control add is specified the “StartupScript” which is a special script that the web client calls once the page is loaded.

THE “STARTUP SCRIPT”

The startup script is a normal JavaScript, the magic happens with this method: Microsoft.Dynamics.NAV.InvokeExtensibilityMethod().

In this script is possibile to invoke extensibility (CallBack methods),

What is InvokeExtensibilityMethod… As from official microsoft documentation: “InvokeExtensibilityMethod Invokes an AL trigger on the Dynamics 365 Business Central service on the page that contains the control add-in”

This file acts as “interface” between those two components: the BC page and the WebApp.

Here i declared events and procedures that are “shared” between the control addin and the page:

THE “SCRIPTS” SECTION

The Scripts property can reference both external and local scripts. I added both my local script and the external knockout library.

The knockout library allows me to use later on this way to load the external page: $.ajax({ url: url, xhrFields: { withCredentials: true } )).done(function(data) { $(“#controlAddIn).text(data); });

The local script contains a CallJavaScript method. This method is declared in the previous “StartupScript” and in consequence is accessible from the Business Central Page as I will describe later. This method is called in my webpage to raise events and call a trigger in the bc page.

THE “PAGE”

The control add-in is placed in the page.

There are two triggers in the page.

Those two triggers have the same signature as in the control add-in.

THE AZURE FUNCTION

The Azure Function returns an HTML5 page.

It contains three content files , those file are read, combined and sent back as an http response.

The interesting part is in the javascript that is called on the OnClick Event of the button.

The javascript function invokes PostToBc() and consequently the trigger in bc is raised.

IFRAME PROBLEMS

As I described on my other article, the iframe solution is not really the best one because this piece of code:

window.parent.document.CallJavaScript(‘OnBcPageCallBack’, [json]);

Does not work and cross site scripting is blocked by default by modern browsers.

https://businesscentraldotblog.wordpress.com/2021/02/28/control-add-in-in-business-central-why-iframes-are-not-a-good-idea/

Thus I used another solution to embed an external static resource on my BC page:

I first included: ‘https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-debug.js&#8217;,

Then I loaded the page with this AJAX function

$.ajax({ url: url, xhrFields: { withCredentials: true } )).done(function(data) { $(“#controlAddIn).text(data); });

SOURCES

Source codes are available:

Business Central Extension: https://github.com/avalonit/ExBcMarameoProdManager

Azure Function WebSite https://github.com/AlbertoValentiVaprime/AzWebMarameoProdManager

REFERENCES

Roberto Stefanetti and Vjieko Control addins

https://github.com/vjekob/TicTacToeAL

LAST UPDATED

26th of February, 2021

My JSON To AL Converter

JSON TO AL CONVERTER

Since I am very lazy and I didn’t find any AL code generator I decided to develop it on my own.

My app gets a JSON file as input and, for each entity present, it automatically generates three files :

1) the AL table ;

2) the AL page ;

3) the AL API page ;

The AL code is SaaS/Cloud ready (I’m not sure if it works on OnPremise, but it should) . It is targeting the current Business Central version : 17.2. I am planning to migrate it as a Visual Studio extension soon.

It’s really simple to use, you have a demo video below.

EXECUTABLE

If you don’t want to compile the VS2019 solution you can get the application executable from here:

http://www.katanet.it/download/JsonToAlConverter.zip

It requires framework installed.

SOURCES

Source code is available.

https://github.com/avalonit/JsonToAlConverter

REFERENCES

This project is a fork of existing C# class generator from JSON.

JSON C# Class Generator (xamasoft.com)

https://www.xamasoft.com/json-class-generator/

LAST UPDATED

8th of January, 2021

23rd of March, 2021 (updated github)

Implementing OData API authorisation in Business Central v17.x (Part 2 integration with Xamarin)

ODATA

Good news: the medieval webkey authentication for Business Central API has finally been deprecated.

In this first article I presented a little overview of the secure and modern OAuth protocol with a “delegated permission” sample.

In this article I describe an “Application permissions” implementation for an application that runs as a background service or daemon without a signed-in user. I am going to describe how I refactored an existing Xamarin mobile application that is currently directly getting and posting data to Business Central APIs.

IT’S TIME TO MOVE TO AZURE

Login in Azure Portal https://portal.azure.com/ , go to “All Services”, search “App Registration” and select “App registrations” list item.

Create a new registration.

Configure your application registration name and the redirect URI As Web with the URL “https://businesscentral.dynamics.com/&#8221;.

Or even better “https://businesscentral.dynamics.com/OAuthLanding.htm

Note down the “Application (client) ID” GUID, this is the “CLIENT ID” we are going to use in Insomia.

Select “API permission” blade,

Configure as in picture, this time we are going to use a different kind of permissions: “Application permission”.

Go the “Certificate and secrets” blade.

Add a new “Client secret”

The “Client secret” and “Secret ID” will be generated,

Please notice that the “Client secret” is shown in clear text ONLY after the first generation and it will NEVER EVER be shown again. If lost you will need to generate a new one. There is not way to recover an existing “Client secret”.

Copy the “Value”, we are going to use it in Insomia as “CLIENT SECRET”.

TEST WITH INSOMNIA

Here are all mandatory parameters to make an OATH request:

Token-Name: Give the appropriate Token Name
Grant Type: Authorization Code

Callback URL: https://businesscentral.dynamics.com/

Auth URL:
https://login.windows.net/<tenant_id>/oauth2/authorize?resource=https://api.businesscentral.dynamics.com
Access Token URL:
https://login.windows.net/<tenant_id>/oauth2/token?resource=https://api.businesscentral.dynamics.com

Client ID: Client ID as in “ID” column in azure
Client Secret: Client Secret Value as in “Value” column in azure.

By using Insomnia you easily test the API:

The well known Microsoft Azure AD web page appears asking for the username.

And the password.. and it’s done.

XAMARIN SOURCES

Will post in a couple of days a sample Xamarin App that gets a list of customers from BC17x API by using OData authorisation. Stay tuned.

SOURCES

Olisterr Tech blog

https://www.olisterr.tech/2020/12/setting-up-oauth-authentication-for.html

Arend-Jan Kauffmann

How to Authenticate Through Azure Active Directory (AAD) to Use Microsoft Dynamics 365 Business Central API: https://www.1clickfactory.com/blog/how-to-authenticate-through-azure-active-directory-to-use-business-central-api/

OAuth Explained with Xamarin.Forms: https://www.codementor.io/@ravitejalingineni/oauth-explained-with-xamarin-forms-q2zomkhda

Adding Auth to your Xamarin.Forms App – Part 2: https://www.heyraviteja.com/post/projects/xam-forms-oauth-part2/

LAST UPDATED

25th of December, 2020

My “step by step” guide for implementing OData API authorisation in Business Central v17.x (Part 1)

ODATA

Good news: the medieval webkey authentication for Business Central API has finally been deprecated.

In this first article I am going to present a little overview of the secure and modern OAuth protocol with a “delegated permission” sample.

In next article I will describe an “Application permissions” implementation for an application that runs as a background service or daemon without a signed-in user. I am going to describe how I refactored an existing Xamarin mobile application that is currently directly getting and posting data to Business Central APIs.

IT’S TIME TO MOVE TO AZURE

Login in Azure Portal https://portal.azure.com/ , go to “All Services”, search “App Registration” and select “App registrations” list item.

Create a new registration.

Configure your application registration name and the redirect URI As Web with the URL “https://businesscentral.dynamics.com/&#8221;.

Or even better “https://businesscentral.dynamics.com/OAuthLanding.htm

Note down the “Application (client) ID” GUID, this is the “CLIENT ID” we are going to use in Insomia.

Select “API permission” blade,

Configure as in picture.

Go the “Certificate and secrets” blade.

Add a new “Client secret”

The “Client secret” and “Secret ID” will be generated,

Please notice that the “Client secret” is shown in clear text ONLY after the first generation and it will NEVER EVER be shown again. If lost you will need to generate a new one. There is not way to recover an existing “Client secret”.

Copy the “Value”, we are going to use it in Insomia as “CLIENT SECRET”.

TEST WITH INSOMNIA

Here are all mandatory parameters to make an OATH request:

Token-Name: Give the appropriate Token Name
Grant Type: Authorization Code

Callback URL: https://businesscentral.dynamics.com/

Auth URL:
https://login.windows.net/<tenant_id>/oauth2/authorize?resource=https://api.businesscentral.dynamics.com
Access Token URL:
https://login.windows.net/<tenant_id>/oauth2/token?resource=https://api.businesscentral.dynamics.com

Client ID: Client ID as in “ID” column in azure
Client Secret: Client Secret Value as in “Value” column in azure.

By using Insomnia you easily test the API:

The well known Microsoft Azure AD web page appears asking for the username.

And the password.. and it’s done.

SOURCES

Olisterr Tech blog

https://www.olisterr.tech/2020/12/setting-up-oauth-authentication-for.html

Arend-Jan Kauffmann

LAST UPDATED

24th of December, 2020

Consume Azure Maps API from Business Central through an Azure Function

THE RECIPE

For every Business Central customer I have to store Lat and Lng coordinates.

Starting form the customer full address, the coordinates are obtained by using Geolocation and Reverse Geolocation APIs of Azure Maps.

The coordinates are finally stored in the Customer table.

The whole procedure is implemented with a time triggered Azure Function acting as a scheduled orchestrator between Business Central API and Azure Maps API.

The next step implementation will automate this process by using webhooks: with this solution Business Central notifies the Azure Function every time a customer entity is updated and the azure function automatically and immediately update the coordinates.

ACTIVATE AND CONFIGURE AZURE MAPS ON AZURE

Login in Azure Portal and create a new source.

After resource is created just grab the primary key from “Authentication” blade.

TEST AZURE MAPS WITH INSOMNIA

The rest call to get the address’s coordinates is pretty simple:

Eg: https://atlas.microsoft.com/search/address/json?subscription-key={key}&api-version=1.0&query=Via Martiri del Popolo, 22, 50055 Lastra a Signa (FI)

By using Insomnia you easily test the API:

The JSON contains the coordinates of given address.

AZURE FUNCTION

The Azure function ProcessCustomers downloads a list of customers by using an API. For each customer it queries Azure Map service to get the lat and lon coordinates from the given address.

First it gets the list of customers by using a custom API and deserialize it.

The Customers.cs contains the business central Customer domain class converted in C# class.

Azure Map API services are used to get the lat and lon coordinates.

The full address is composed by formatting the business central address fields to obtain an Azure Map compliant address.

The Azure Map returns a JSON as represented in AzureMapResults.cs class file.

This is a typical json as returned from Azure Maps services:

The coordinates are updated in Business Central by using an http PATCH request on my custom API.

The patch request has the standard format: The If-Match header represents the entity ETag as returned from Business Central and the Query URL must contain the filter by using the primary key field (No in my case).

If the PATCH request succeeded the API returns the new updated entity.

ETAG: PAY ATTENTION!!!

The Etag is updated every time an entity in modified in Business Central. This means the Etags are loaded when the azure function is called and if an user change some field in Bc this Etag is changed too.

In this case the Http PATCH request will be denied because we try to update a record that has changed on ERP and it will return an “Http 409 Conflict” error.

SOURCES

https://github.com/avalonit/AzAPP365AzureMaps

LAST UPDATED

9th of September, 2020

Azure Cognitive and Business Central : “Form Recognizer” API integration

Easily track employee expenses (Part 2 – Business Central AL code).

How to get the receipt grand total from an image by using Azure Cognitive API and save it Business Central.

HOW TO TEST OUR CUSTOM MODEL WITH INSOMNIA

Let’s have a look on how cognitive requests work by using Insomia.

First of all I make a POST call with a Json with the format:.

https://{ my address }.cognitiveservices.azure.com//formrecognizer/v2.0-preview/custom/models/ { my model id } /analyze

The posted json contains the source URL of the blob image in source.

The header contain the Cognitive Key in “Ocp-Apim-Subscription-Key”.

You should get back a “202 – Accepted” containing Operation-Location which is the URL to be queried to get the result.

The “Operation Location” to be queried to get back the result has the following format.

https://{service name}.cognitiveservices.azure.com/formrecognizer/v2.0-preview/custom/models/{model id}/analyzeresults/{result id}

By calling with a GET the URL we finally get the tags we trained with our custom model.

BUSINESS CENTRAL AL

The codeunit 70659914 “ALV Cognitive Service API” contains the logic to call the azure cognitive API.

GetCognitive() makes the first call to cognitive to start the blob storage image processing by using custom model.

The GetCognitiveResult() queries the Cognitive API waiting for the result to be evaluated.

Source code in AL available here:

https://github.com/avalonit/ExBcCognitiveAzure

CREDITS

AL support for REST Web Services by Kauffmann

AL support for REST Web Services

LAST UPDATED

22st of July, 2020

Azure Cognitive and Business Central : “Form Recognizer” API integration

Easily track employee expenses (Part 1 – training).

How to get the receipt grand total from an image by using Azure Cognitive API and save it Business Central.

SCENARIO

  • The user, by using a mobile device, takes the photo of the receipt and uploads to an azure blob storage;
  • The Azure “Form Recognizer” API service automatically recognise the receipt grand total;
  • Business Central automatically fills the employee expense grand total;

WHAT IS NEEDED

  • A blog storage to store images.
  • An Azure Form Recognizer account.
  • A docker image to train a custom model.
  • A custom Business Central AL codeunit

AZURE COGNITIVE SERVICES

Azure cognitive services offers a variety of APIs:

https://westus2.dev.cognitive.microsoft.com/docs/services/form-recognizer-api-v2/operations/AnalyzeReceiptAsync

Among all the available features, “Form Recognizer” allows to detect part of a receipt.

At the moment “Form Recognizer”, just out of beta stage, only applies to UK/USA receipts and isn’t yet able to correctly detect grand totals with EU receipts.

This means it’s necessary to train a custom model to get better results.

https://docs.microsoft.com/en-gb/azure/cognitive-services/form-recognizer/overview#train-with-labels

To create the service is as easy as three mouse clicks: Add Resource, select “Form Recognizer” from list, configure names and location/resource group.

Once the service has been created, under Keys and Endpoints you can find “Key 1” and “Endpoint”, these two strings will be used when configuring Label Tools.

AZURE BLOB STORAGE

I create a blob container on Azure Portal and I upload there all of my receipts by using “Storage Explorer”.

It’s important to enable “Configure cross-domain resource sharing (CORS)” access.

HOW TO CREATE AND TRAIN A CUSTOM MODEL

Since the service by default recognises only US/UK receipts I have to create my own custom model.

To create a custom model I followed official microsoft instructions https://docs.microsoft.com/it-it/azure/cognitive-services/form-recognizer/quickstarts/label-tool

I installed docker, and switched to Linux containers (unfortunately the label tools requires a linux container instead of a Windows container).

Just with two lines are enough to have the container up and running:

First I pull the label tool container:

docker pull mcr.microsoft.com/azure-cognitive-services/custom-form/labeltool 

Then I start the container:

docker run -it -p 3000:80 mcr.microsoft.com/azure-cognitive-services/custom-form/labeltool eula=accept

It’s now possibile to open the web console from local browser:

http://localhost:3000/

First of all I configured connection with the blob storage, then I configured the form recognizer endpoint and API key from previous chapter.

The web application imports all of the images from blob storage.

I create my own tag as a numeric.

Now the boring part, for each of the image I manually assign the tag to the corresponding text on receipt.

Now it’s time to start the training.

After a couple of minutes I get the result of training session:

The web console allows to test the custom model on receipts by uploading them.

COMING SOON

In next article I will cover how to call the Cognitive API from a Business Central codeunit.

https://businesscentraldotblog.wordpress.com/2020/07/22/azure-cognitive-and-business-central-integrate-form-recognizer-api-and-automatically-process-receipts-by-using-al-language/

LAST UPDATED

21st of July, 2020