Connect to Azure Function in BC 2022 wave 2 (v21)

by Oct 15, 2022AL Language

Home 9 Development 9 AL Language 9 Connect to Azure Function in BC 2022 wave 2 (v21)

The new version of the Microsoft Dynamics 365 Business Central brought a new system module “Azure Functions” that makes integration with Azure Functions much easier and straightforward. The typical scenario, why to use Azure Functions together with Business Central, is if we need to use the .NET interop component (for example custom DLL) from AL. Some examples of why I use Azure Functions are creating integration with SFTP (to send warehouse data to old-school shipping agents), loading data from machines in manufacturing, or just signing documents using SignPads.

The new module contains three (public) codeunits.

  • Azure Functions (codeunit 7804)
  • Azure Functions Authentication (codeunit 7800)
  • Azure Functions Response (codeunit 7805)

Authentication

Let’s start with authentication. There are two possible ways how to use this module from the point of authentication. If your Azure Function is secured at function-level only (= without user identification), we can use the method CreateCodeAuth(…) from Codeunit 7800 “Azure Functions Authentication”. This method accepts two parameters, Azure Functions endpoint (URL) and authentication code that is defined for your Azure Function. This approach is far from ideal as anyone who knows this code can access your Azure Functions.

The second method is CreateOAuth2(…) which allows creating a connection with both OAuth2 and the Authentication code for your function.

Both these methods return an instance of codeunit that implements an interface “Azure Functions Authentication” which is later used for API requests.

Create own integration

Once we know the authentication methods, we know everything necessary to build our integration. To send a GET request to our Azure Function we can use the method SendGetRequest(…) available in Codeunit 7804 “Azure Functions”.

This method has two parameters, the first one is the implementation of Azure Functions Authentication that we discussed earlier. The second one is a Dictionary of Texts that will be translated to URL parameters (the dictionary key = parameter name, dictionary value = parameter value).

Method SendGetRequest(…) returns an instance of another codeunit, Codeunit 7805 “Azure Functions Response”. This object contains all information about the API response, including whether the API call was successful (method IsSuccessful()). You can also get error information (GetError()), response content (GetResultAsText(…), GetResultAsStream(…)) or whole instance of HttpResponseMessage (GetHttpResponse(…)).

procedure SendAzureFunctionGetRequest()
var
    AzureFunctions: Codeunit "Azure Functions";
    AzureFunctionsResponse: Codeunit "Azure Functions Response";
    AzureFunctionsAuthentication: Codeunit "Azure Functions Authentication";
    IAzureFunctionsAuthentication: Interface "Azure Functions Authentication";
    QueryDictinary: Dictionary of [Text, Text];
begin
    QueryDictinary.Add('param1', 'value1');
    QueryDictinary.Add('param2', 'value2');
    QueryDictinary.Add('param3', 'value3');

    IAzureFunctionsAuthentication := AzureFunctionsAuthentication.CreateCodeAuth('AZURE FUNCTION ENDPOINT', 'AUTHENTICATION CODE');
    AzureFunctionsResponse := AzureFunctions.SendGetRequest(IAzureFunctionsAuthentication, QueryDictinary);
    if AzureFunctionsResponse.IsSuccessful() then
        Message('Get request successful.')
    else
        Error('Get request failed.\Details: %1', AzureFunctionsResponse.GetError());
end;

The POST request could be created similarly – we just need to use the SendPostRequest(…) method instead of SendGetRequest(…). This time, the method does not accept Dictionary, but RequestBody (only as Text) and Content-Type header.

Unfortunately, I really miss something like SendPostRequest(AzureFunctionAuthentication: Interface “Azure Functions Authentication”; Body: JsonObject) as it will be much easier to use…

procedure SendAzureFunctionPostRequest()
var
    AzureFunctions: Codeunit "Azure Functions";
    AzureFunctionsResponse: Codeunit "Azure Functions Response";
    AzureFunctionsAuthentication: Codeunit "Azure Functions Authentication";
    IAzureFunctionsAuthentication: Interface "Azure Functions Authentication";
    RequestBody: Text;
    JsonObject: JsonObject;
begin
    JsonObject.Add('param1', 'value1');
    JsonObject.Add('param2', 'value2');
    JsonObject.Add('param3', 'value3');

    JsonObject.WriteTo(RequestBody);
    IAzureFunctionsAuthentication := AzureFunctionsAuthentication.CreateCodeAuth('AZURE FUNCTION ENDPOINT', 'AUTHENTICATION CODE');
    AzureFunctionsResponse := AzureFunctions.SendPostRequest(IAzureFunctionsAuthentication, RequestBody, 'application/json');
    if AzureFunctionsResponse.IsSuccessful() then
        Message('Post request successful.')
    else
        Error('Post request failed.\Details: %1', AzureFunctionsResponse.GetError());
end;

There is also an available universal method Send(…), which allows using any HTTP Request Type and defining both Header & Body content.

procedure SendAzureFunctionUniversalRequest()
var
    AzureFunctions: Codeunit "Azure Functions";
    AzureFunctionsResponse: Codeunit "Azure Functions Response";
    AzureFunctionsAuthentication: Codeunit "Azure Functions Authentication";
    IAzureFunctionsAuthentication: Interface "Azure Functions Authentication";
    HttpRequestType: Enum "Http Request Type";
    QueryDictinary: Dictionary of [Text, Text];
    RequestBody: Text;
    JsonObject: JsonObject;
begin
    QueryDictinary.Add('urlParam1', 'urlValue1');
    QueryDictinary.Add('urlParam2', 'urlValue2');
    JsonObject.Add('bodyParam1', 'bodyValue1');
    JsonObject.Add('bodyParam2', 'bodyValue2');

    JsonObject.WriteTo(RequestBody);
    IAzureFunctionsAuthentication := AzureFunctionsAuthentication.CreateCodeAuth('AZURE FUNCTION ENDPOINT', 'AUTHENTICATION CODE');
    AzureFunctionsResponse := AzureFunctions.Send(IAzureFunctionsAuthentication, HttpRequestType::/*METHOD*/, QueryDictinary, RequestBody, 'application/json');
    if AzureFunctionsResponse.IsSuccessful() then
        Message('Universal request successful.')
    else
        Error('Universal request failed.\Details: %1', AzureFunctionsResponse.GetError());
end;

In my opinion, this new system module made the integration with Azure Functions a bit easier as we do not longer need to set all headers manually and also we do not have to think about the implementation of authentication.

What do you think? Let me know by sharing this article on Twitter/LinkedIn.

Recent Articles from the category

Collectible Errors?! Is it already in use?

Collectible Errors?! Is it already in use?

Collectible Errors?! Is it already in use? This is the second part of my new article series about Collectible Errors. Let's check out the first part here: Collectible Errors?! | Microsoft Dynamics 365 - Ing. Tomáš Kapitán (kepty.cz) or you might be interested in my...

read more
Collectible Errors?!

Collectible Errors?!

Collectible Errors?! It has been already almost a year since ErrorInfo datatype & CollectibleErrors were introduced (I already have an article about basic structure: ErrorInfo data type & Collectible Errors). This article was released for the first time in...

read more
Substituting standard reports

Substituting standard reports

Report objects cannot be extended in versions previous to the Business Central 2021 release wave 1 version when ReportExtensions object was introduced. Since then, many of changes we need to do in reports can be done without creating a new copy of object. On the other...

read more
Isolated events

Isolated events

With Business Central 2022 wave 1, a new setting for event publishers was introduced. Until this version, any error in any event subscriber caused interruption to the current running process and stopped the whole activity. In some cases (such as log-in), this is...

read more
Custom Filter Tokens

Custom Filter Tokens

As a user of the Business Central you have some constants you can use to filter or insert values. These constants contain useful values for data manipulation such as t / today for date field - return current dateq / quarter for date field filters - return range of the...

read more
1D & 2D Barcodes in Business Central 19.1

1D & 2D Barcodes in Business Central 19.1

Business Central (cloud-only!) includes one-dimensional (1D) barcode fonts since Microsoft Dynamics 365 Business Central 2020 wave 2 (17.0) was released in October 2020. It is a great improvement to how developers can handle requirements from their clients to print...

read more
How to let users choose field(s) properly

How to let users choose field(s) properly

When some complex functionality is developed, it is sometimes necessary to let users choose a specific field. This can be required for field permissions, mapping imported values or any similar process. Earlier, the usual way was to create a link on the Field table...

read more

Sign Up for News

Certifications

Highest certification
Microsoft Data Management and
also in D365 Business Central

Microsoft Certified: Dynamics 365 Business Central Functional Consultant Associate

See other certifications here