Henter seneste Business Central nyheder…
Udvikling

25. januar 2025 Lauge Koch-Klarskov 9 min læsning

Det meste kan og bør bygges i AL. Men AL i Business Central online har grænser: ingen .NET-biblioteker, ingen filsystemadgang, ingen lange beregninger uden at låse brugeren. Når vi rammer dem, lægger vi logikken i en Azure Function og kalder den fra AL.

Den her guide viser, hvornår det giver mening, hvordan et minimalt setup ser ud, og hvilke fejl vi ser igen og igen.

Forståelse af Azure Functions

Kort sagt: et lille stykke kode i Azure, der kører, når noget kalder det, og som I kun betaler for, mens det kører.

Hvad er Azure Functions?

En Azure Function er en serverløs funktion, der startes af en trigger: et HTTP-kald, en timer, en besked på en kø eller en ny fil i Blob Storage. I skriver funktionen i C#, JavaScript, Python eller PowerShell, og Azure sørger for at køre den. På Consumption- eller Flex Consumption-planen betaler I per kørsel, og for de fleste BC-integrationer ender regningen på få kroner om måneden.

Vigtige fordele ved Business Central-integration

Hvorfor ikke bare skrive det hele i AL? Fordi en Function kan ting, AL online ikke kan:

  • Fuld .NET med NuGet-pakker — fx til PDF-behandling, SFTP, kryptering eller et leverandør-SDK
  • Kører uden for BC's sessionstid, så tunge job ikke blokerer brugeren eller job-køen
  • Kan modtage webhooks fra webshops og andre systemer og skrive til BC via API'et
  • Timer-triggers til faste kørsler, uafhængigt af BC's job-kø
  • Secrets i Azure Key Vault i stedet for i en setup-tabel
  • Logning i Application Insights, samme sted som BC-telemetrien
Vores kunder, der har implementeret Azure Functions med Business Central, har set udviklingstiden for brugerdefinerede udvidelser reduceret med op til 60% sammenlignet med traditionelle udvidelsesmetoder, samtidig med at de forbedrer skalerbarhed og reducerer driftsomkostninger.

Almindelige anvendelsestilfælde

Det er de scenarier, hvor vi typisk vælger en Function frem for ren AL:

Brugerdefinerede API-integrationer

Fragtfirmaer, branchesystemer og ældre løsninger, der kun taler SOAP med klientcertifikat, SFTP eller et proprietært filformat. Functionen oversætter til et rent JSON-kald, som AL kan håndtere. Typiske eksempler: indlæsning af kontoudtog fra en SFTP-server, eller afsendelse af ordrer til et 3PL-lager, der kun accepterer CSV på en FTP.

Baggrundsbehandling

Skal en webshop sende 2.000 ordrer på én gang, eller skal et prisark med 50.000 linjer indlæses, er det ikke noget, en bruger skal vente på. Functionen tager imod, lægger opgaven på en kø og skriver til BC i bidder via API'et. BC's job-kø kan også meget, men den deler kapacitet med alt andet i miljøet.

Komplekse beregninger og forretningslogik

Fragtberegning med zonetabeller, punktafgiftsberegning på tværs af mange varegrupper eller generering og signering af PDF'er. Det kan godt skrives i AL, men det er ofte hurtigere og nemmere at teste i C# med et færdigt bibliotek. Hold forretningsreglerne i BC og selve beregningen i Functionen, så konsulenten stadig kan se, hvad der sker.

Planlagte opgaver og overvågning

Timer-triggers er gode til natlige synkroniseringer, valutakurser fra en ekstern kilde eller et dagligt tjek af, om integrationerne faktisk har kørt. De er også det oplagte sted at forny webhook-abonnementer i BC, som udløber efter tre dage, hvis ingen fornyer dem.

Opsætning af dit udviklingsmiljø

Det er hurtigt sat op, hvis I allerede udvikler AL i VS Code.

Forudsætninger

I skal bruge:

  • Et Azure-abonnement — gerne i samme Entra-tenant som Business Central
  • Visual Studio Code med Azure Functions-udvidelsen og C# Dev Kit
  • Azure Functions Core Tools v4 og .NET 8 SDK
  • En Business Central sandbox til test — aldrig direkte mod produktion
  • En app-registrering i Entra ID, hvis Functionen skal kalde tilbage til BC's API

Oprettelse af dit første Azure Function-projekt

Sådan opretter I et projekt i VS Code:

  1. Tryk F1 og vælg 'Azure Functions: Create New Project'.
  2. Vælg en tom mappe til projektet.
  3. Vælg C# og runtime '.NET 8.0 Isolated'. Vælg ikke in-process — den model mister support 10. november 2026.
  4. Vælg skabelonen 'HTTP trigger'.
  5. Giv funktionen et navn og vælg autorisationsniveauet 'Function', så kald kræver en nøgle.
  6. Kør projektet lokalt med F5 og test det med en POST fra fx REST Client, før I deployer.

Grundlæggende HTTP-trigger funktionseksempel

Et minimalt eksempel i isolated worker-modellen, der modtager et bilagsnummer fra BC og svarer med JSON:

using System.Net;
using System.Text.Json;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;

namespace Invice.BCFunctions;

// Isolated worker model (.NET 8). In-process-modellen mister support 10. november 2026.
public class ProcessBusinessCentralData(ILogger<ProcessBusinessCentralData> logger)
{
    [Function("ProcessBusinessCentralData")]
    public async Task<HttpResponseData> Run(
        [HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req)
    {
        using var doc = await JsonDocument.ParseAsync(req.Body);
        var documentNo = doc.RootElement.GetProperty("documentNo").GetString();

        logger.LogInformation("Behandler {DocumentNo} fra Business Central", documentNo);

        // Forretningslogikken her. Hold den kort: brugeren i BC venter på svaret.

        var response = req.CreateResponse(HttpStatusCode.OK);
        await response.WriteAsJsonAsync(new { documentNo, status = "processed" });
        return response;
    }
}

Integrationsmønstre med Business Central

Der er tre mønstre, vi bruger: BC kalder Functionen direkte (synkront), BC lægger en besked, som Functionen behandler senere (asynkront), eller et eksternt system kalder Functionen, som så skriver til BC via API'et. Det første er det mest almindelige, så det viser vi her.

HTTP-udløste funktioner

BC kalder Functionen med HttpClient og venter på svaret. Det passer til opslag og beregninger, der tager under et par sekunder: en fragtpris, en adressevalidering, en genereret PDF. Tager det længere, så gør det asynkront.

Eksempel på AL-kode, der kalder Functionen ovenfor:

procedure CallAzureFunction(Payload: JsonObject) Result: JsonObject
var
    Client: HttpClient;
    Request: HttpRequestMessage;
    Response: HttpResponseMessage;
    Content: HttpContent;
    ContentHeaders: HttpHeaders;
    RequestHeaders: HttpHeaders;
    PayloadText: Text;
    ResponseText: Text;
begin
    Payload.WriteTo(PayloadText);
    Content.WriteFrom(PayloadText);
    Content.GetHeaders(ContentHeaders);
    ContentHeaders.Remove('Content-Type');
    ContentHeaders.Add('Content-Type', 'application/json');

    Request.Method := 'POST';
    Request.SetRequestUri(GetFunctionUrl());   // fra en setup-tabel, ikke hardkodet
    Request.Content := Content;
    Request.GetHeaders(RequestHeaders);
    RequestHeaders.Add('x-functions-key', GetFunctionKey());   // gemt i IsolatedStorage, ikke i URL'en

    Client.Timeout := 30000;   // standard er 100 sekunder, og brugeren venter imens

    if not Client.Send(Request, Response) then
        Error('Azure Function kunne ikke kaldes: %1', GetLastErrorText());
    if not Response.IsSuccessStatusCode() then
        Error('Azure Function svarede %1: %2', Response.HttpStatusCode(), Response.ReasonPhrase());

    Response.Content.ReadAs(ResponseText);
    Result.ReadFrom(ResponseText);
end;

De fejl, vi oftest ser:

  • Function-nøglen står i URL'en som ?code=… og ender i logs og telemetri. Send den som x-functions-key-header.
  • Returværdien fra Client.Send ignoreres, så en netværksfejl bliver til en uforståelig runtime-fejl for brugeren.
  • Det virker i produktion, men ikke i sandboxen: udgående HTTP-kald er blokeret som standard i sandboxes og kopierede miljøer. Slå 'Allow HttpClient Requests' til under Extension Management → Configure.
  • Ingen timeout sat. Standarden er 100 sekunder, og det er lang tid at stirre på et timeglas.
  • URL og nøgle hardkodet i AL, så sandbox og produktion rammer samme Function.

Har I en integration, AL ikke kan løse alene?

Vi bygger både AL-extensionen og Azure Functionen bag den, og vi drifter den bagefter. Du taler med den udvikler, der skriver koden.

Kontakt os

Relaterede artikler

Mere om Business Central og cloud-migration.

Fortæl os, hvad jeres Business Central skal kunne.

Skriv eller ring, så vender en af os tilbage samme arbejdsdag. Første samtale er en halv time, og I går fra den med en konkret vurdering af, hvad jeres opgave kræver.