Miklix

Ringer til AIF Document Services direkte fra X++ i Dynamics AX 2012

Udgivet: 16. februar 2025 kl. 11.22.53 UTC
Sidst opdateret: 12. januar 2026 kl. 08.55.11 UTC

I denne artikel forklarer jeg, hvordan man kalder Application Integration Framework-dokumenttjenester i Dynamics AX 2012 direkte fra X++-kode, og emulerer både indgående og udgående kald, hvilket kan gøre det betydeligt nemmere at finde og foretage fejlfinding i AIF-kode.


Denne side er blevet maskinoversat fra engelsk for at gøre den tilgængelig for så mange mennesker som muligt. Desværre er maskinoversættelse endnu ikke en perfekt teknologi, så der kan forekomme fejl. Hvis du foretrækker det, kan du se den originale engelske version her:

Calling AIF Document Services Directly from X++ in Dynamics AX 2012

Oplysningerne i dette indlæg er baseret på Dynamics AX 2012 R3. De er muligvis ikke gyldige for andre versioner.

Jeg hjalp for nylig en kunde med at implementere en Application Integration Framework (AIF) inbound port til oprettelse af kunder baseret på data, de modtog fra et andet system. Da Dynamics AX allerede leverer dokumenttjenesten CustCustomer, som implementerer logikken bag dette, besluttede vi at holde det enkelt og bruge standardløsningen.

Det viste sig dog hurtigt, at der var en del problemer med at få det eksterne system til at generere XML, som Dynamics AX ville acceptere. XML-skemaet genereret af Dynamics AX er ret komplekst, og det ser også ud til, at der er et par fejl i Dynamics AX, der nogle gange får det til at afvise XML, der er skema-gyldigt ifølge andre værktøjer, så alt i alt viste det sig at være mindre simpelt, end jeg havde troet.

Undervejs kæmpede jeg ofte med at finde ud af, præcis hvad problemet var med visse XML-filer, fordi fejlmeddelelserne fra AIF er mindre informative. Det var også kedeligt, fordi jeg var nødt til at vente på, at det eksterne system sendte en ny besked via MSMQ, og derefter igen på, at AIF opfangede beskeden og behandlede den, før jeg kunne se en fejl.

Jeg undersøgte derfor, om det er muligt at kalde servicekoden direkte med en lokal XML-fil for at opnå en noget hurtigere test, og det viser sig, at det er det - og ikke nok med det, det er virkelig nemt at gøre og giver faktisk langt mere meningsfulde fejlmeddelelser.

Eksempeljobbet nedenfor læser en lokal XML-fil og forsøger at bruge den sammen med AxdCustomer-klassen (som er den dokumentklasse, der bruges af CustCustomer-tjenesten) til at oprette en kunde. Du kan lave lignende job for alle de andre dokumentklasser, f.eks. AxdSalesOrder, hvis du har brug for det.

static void CustomerCreate(Args _args)
{
    FileNameOpen fileName    = @'C:\\TestCustomerCreate.xml';
    AxdCustomer  customer;
    AifEntityKey key;
    #File
    ;

    new FileIoPermission(fileName, #IO_Read).assert();

    customer = new AxdCustomer();

    key = customer.create(  XmlDocument::newFile(fileName).xml(),
                            new AifEndpointActionPolicyInfo(),
                            new AifConstraintList());

    CodeAccessPermission::revertAssert();

    info('Done');
}

AifEntityKey-objektet, der returneres af customer.create()-metoden (som svarer til "create"-serviceoperationen i AIF), indeholder oplysninger om, hvilken kunde der blev oprettet, blandt andet RecId'et for den oprettede CustTable-post.

Hvis det, du prøver at teste, i stedet er en udgående port, eller hvis du bare har brug for et eksempel på, hvordan XML'en skal se ud på den indgående port, kan du også bruge dokumentklassen til at eksportere en kunde til en fil ved at kalde read()-metoden (svarende til "read"-serviceoperationen) i stedet, således:

static void CustomerRead(Args _args)
{
    FileNameSave    fileName = @'C:\\TestCustomerRead.xml';
    Map             map      = new Map( Types::Integer,
                                        Types::Container);
    AxdCustomer     customer;
    AifEntityKey    key;
    XMLDocument     xmlDoc;
    XML             xml;
    AifPropertyBag  bag;
    #File
    ;

    map.insert(fieldNum(CustTable, AccountNum), ['123456']);
    key = new AifEntityKey();
    key.parmTableId(tableNum(CustTable));
    key.parmKeyDataMap(map);
    customer = new AxdCustomer();

    xml = customer.read(key,
                        null,
                        new AifEndpointActionPolicyInfo(),
                        new AifConstraintList(),
                        bag);

    new FileIoPermission(fileName, #IO_Write).assert();
    xmlDoc = XmlDocument::newXml(xml);
    xmlDoc.save(fileName);
    CodeAccessPermission::revertAssert();
    info('Done');
}

Du skal selvfølgelig erstatte '123456' med kontonummeret på den kunde, du ønsker at aflæse.

Yderligere læsning

Hvis du kunne lide dette indlæg, kan du måske også lide disse forslag:


Del på BlueskyDel på FacebookDel på LinkedInDel på TumblrDel på XDel på LinkedInFastgør på Pinterest

Mikkel Christensen

Om forfatteren

Mikkel Christensen
Mikkel er skaberen og ejeren af miklix.com. Han har over 20 års erfaring som professionel computerprogrammør/softwareudvikler og er i øjeblikket fuldtidsansat i en stor europæisk IT-virksomhed. Når han ikke blogger, bruger han sin fritid på en lang række interesser, hobbyer og aktiviteter, som i et vist omfang afspejles i de mange forskellige emner, der dækkes på dette websted.