Del via


Introduktion til Microsoft Dynamics 365-web-API'en (JavaScript på klientsiden)

 

Udgivet: januar 2017

Gælder for: Dynamics 365 (online), Dynamics 365 (on-premises), Dynamics CRM 2016, Dynamics CRM Online

I HTML-webressourcer, formularscripts eller båndkommandoer kan du bruge JavaScript til at udføre handlinger på Microsoft Dynamics 365-data ved hjælp af Web API introduceret med Microsoft Dynamics 365 (online og i det lokale miljø).

Web API er især let at bruge med JavaScript og webressourcer, da JSON-data, der sendes og modtages med den nemt konverteres til JavaScript-objekter. De fleste udviklere vil dog stadig oprette eller bruge et JavaScript Hjælp-bibliotek for at drage fordel af kodegenbrug og holde deres forretningslogikkode adskilt fra deres kode til at gå adgang til data. Dette emne beskriver, hvordan du kan bruger XMLHttpRequest-objektet til at udføre handlinger med JavaScript samt salgsmuligheder for at oprette genbrugelige JavaScript-biblioteker, der leverer funktioner, som arbejder sammen med Web API.

Dette emne indeholder

Hvor du kan bruge JavaScript på klientsiden

Forstå XMLHttpRequest

Bruge XMLHttpRequest

Oprette JSON-data, der skal sendes

Fortolke JSON-returneret

Oprette en funktion, der kan genbruges, ved hjælp af tilbagekald

Oprette en funktion, der kan genbruges, ved hjælp af tilsagn

Hvor du kan bruge JavaScript på klientsiden

Der er to områder, hvor du kan bruge JavaScript på klientsiden til at få adgang til Microsoft Dynamics 365 ved hjælp af web-API'en:

Forstå XMLHttpRequest

Når du bruger Web API, bruges et XMLHttpRequest-objekt.XMLHttpRequest (XHR) er et indbygget objekt, der findes i alle moderne browsere, og som aktiverer AJAX-teknikker for at gøre websider dynamiske. Selvom navnet på objektet indeholder "XML", bruger alle anmodninger, der bruger Web API'en, JSON i stedet for XML.

XMLHttpRequest bruges af JavaScript-strukturer

JavaScript-strukturer, såsom jQuery, ombryder ofte det underliggende XMLHttpRequest-objekt i en funktion (f.eks. $.ajax) da ikke alle browsere tidligere har angivet en indbygget XMLHttpRequest på en standardiseret måde og til at forenkle anvendelsen. Nu, hvor moderne browsere som standard har implementeret XMLHttpRequest, behøver du ikke et separat bibliotek til at mindske disse forskelle. Men mange udviklere er fortsat afhængige af JavaScript-strukturer for at anmode om serverressourcer. Selvom det er fint at bruge jQuery og andre JavaScript-strukturer i HTML-webressourcer eller SPA'er, anbefaler vi at undgå dem i formularscripts eller kommandoer på båndet. Med forskellige løsninger, der kan være installeret i en organisation, kan alle potentielt have forskellige versioner af en JavaScript-struktur, især jQuery, hvilket kan føre til uventede resultater, medmindre alle gennemfører trin for at undgå konflikter. Hvis du vil udføre Web API-anmodninger i formularscripts eller på kommandoer på båndet, anbefaler vi, at du bruger XMLHttpRequest direkte og ikke bliver afhængige af jQuery.Flere oplysninger:Brug af jQuery

Dette emne beskriver, hvordan du bruger indbyggede XMLHttpRequest direkte, men de samme begreber gør sig gældende, når du bruger jQuery eller andre JavaScript-strukturer, som kører i en browser, da de alle bruger XMLHttpRequest. Du kan bruge et bibliotek, som bruger XHR direkte i en browser med en JavaScript-struktur.

Bruge XMLHttpRequest

Følgende er et meget simpelt eksempel, der viser, hvordan du opretter et kontoobjekt ved hjælp af Web API og XMLHttpRequest-objektet. I dette eksempel er kun clientURL-variablen ikke defineret.

var req = new XMLHttpRequest()
req.open("POST",encodeURI(clientURL + "/api/data/v8.1/accounts"), true);
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.onreadystatechange = function () {
 if (this.readyState == 4 /* complete */) {
  req.onreadystatechange = null;
  if (this.status == 204) {
   var accountUri = this.getResponseHeader("OData-EntityId");
   console.log("Created account with URI: "+ accountUri)
  }
  else {
   var error = JSON.parse(this.response).error;
   console.log(error.message);
  }
 }
};
req.send(JSON.stringify({ name: "Sample account" }));

I følgende afsnit beskrives, hvad denne kode gør.

Åbn XMLHttpRequest

Når du har initialiseret XMLHttpRequest-objektet, skal du åbne den, før du kan angive egenskaber eller sende det.open-metodeparametrene er en HTTP-anmodningsmetode, en URL og en boolean-parameter, der angiver, om operationen skal udføres asynkront. Du bør altid vælge at udføre handlinger asynkront.Flere oplysninger:Brug asynkrone dataadgangsmetoder

Da vi opretter et firmaobjekt, skal vi i dette eksempel angive URL-adressen, så den matcher objektsætstien for account EntityType. Den fulde URL i dette eksempel er clientURL + "/api/data/v8.1/accounts og clientURL-variablen skal være angivet til URL-roden for dette Microsoft Dynamics 365-program. For webressourcer, der har adgang til kontekstobjektet, kan getClientUrl-funktionen, der kan fås adgang til enten via klientsidens kontekstobjekt, som er tilgængelig enten via GetGlobalContext-funktion i en HTML-webressource eller Xrm.Page.context-objektet i et formularscript eller båndkommandoen. Du skal bruge encodeURI-funktionen på en URL, du sender til service for at sikre, at den ikke indeholder usikre tegn.

Da denne funktion opretter et objekt, er HTTP-anmodningsmetoden POST som beskrevet i Oprette et objekt ved hjælp af Web-API.

XMLHttpRequestopen-metoden giver også mulighed for at angive et brugernavn og en adgangskode. Du behøver ikke at angive en værdi for disse parametre med webressourcer, da brugeren allerede er godkendt. For SPA administreres godkendelsen via et token i stedet for disse parametre.

Angiv sidehoveder og hændelseshandler

Når du har åbnet XMLHttpRequest, kan du anvende en række anmodningsheadere ved hjælp af setRequestHeader-metoden. Du bør generelt bruge headerne vist her med nogle variationer for særlige former for forretninger.Flere oplysninger:HTTP-headere.

Før du sender anmodningen, skal du medtage en hændelseshandler, der registrerer, når handlingen er fuldført. Når du har sendt anmodningen, bevæger den sig gennem flere tilstande, før svaret returneres. For at indfange det øjeblik, hvor XMLHttpRequest er fuldført, skal du angive en hændelseshandler for onreadystatechange-egenskaben for at registrere, hvornår readystate-egenskaben er lig med 4, som angiver fuldført. På dette tidspunkt kan du undersøge status-egenskaben.

Bemærk

Når XMLHttpRequest er fuldført, er den bedste fremgangsmåde at angive onreadystatechange-egenskaben til null for at undgå potentielle problemer med hukommelsesfejl.

Inden for den anonyme funktion, som er din hændelseshandler, når du har kontrolleret, at den er afsluttet, kan du undersøge status-egenskaben for at afgøre, om handlingen lykkedes. I dette tilfælde er den forventede statusværdi 204 No Content, da ingenting forventes i brødteksten i svaret fra oprettelseshandling.URI for den oprettede konto er i OData-EntityId-overskriften og kan åbnes ved hjælp af getResponseHeader-metoden.

Hvis dette var en anden handling, der forventedes at returnere data i svaret, ville det have en 200 OKstatus-værdi, og funktionen ville bruge JSON.parseXMLHttpRequest-svaret for at konvertere JSON-svaret i et JavaScript-objekt, som din kode kan få adgang til.Flere oplysninger:Fortolke JSON-returneret

Hvis status ikke er den forventede værdi, er det en fejl, og et fejlobjekt returneres med de egenskaber, der er beskrevet i Fejlmeddelelse fra svaret under opdeling af tekst. I dette eksempel bruges JSON.parse til at konvertere XMLHttpRequestresponse-egenskaben i et JavaScript-objekt, så message-egenskaben kan åbnes.

Send XMLHttpRequest

Endelig kan du bruge XMLHttpRequestsend-metoden til at sende anmodningen, herunder alle JSON-data, der kræves. Brug JSON.stringify til at konvertere JavaScript-objekter til JSON-strenge, der kan medtages i brødteksten i anmodningen, når du sender den.

Oprette JSON-data, der skal sendes

I det foregående eksempel blev firma objektet oprettet med blot et enkelt egenskabssæt. For at bestemme hvilke egenskaber der er tilgængelige for et objekt, skal du kigge på CSDL-metadatadokument, dokumentation, der er genereret fra dette dokument eller kode, der genereres ved hjælp af dette dokument. For systemforretningsobjekter, der er inkluderet i alle Microsoft Dynamics 365-organisationer, kan du se Web API EntityType Reference. Egenskabsnavnene er små bogstaver og accepterer simple datatyper, der svarer til følgende JavaScript type: Boolean, Number, String, Array, Object og Date.

Bemærk

Den eneste undtagelse til at bruge simple datatyper er BooleanManagedProperty ComplexType, der bruges til objekter, som gemmer løsningsspecifikke data som webressourcer, skabeloner, rapporter, roller, gemte forespørgsler og i metadataobjekter. Denne egenskab bruges aldrig til objekter, der lagrer forretningsdata. Metadataobjekter bruger mange komplekse typer og følger forskellige regler. Du kan finde flere oplysninger i Bruge Web API med Dynamics 365-metadata.

Skrivning af data, der skal sendes i en anmodning, er som regel et spørgsmål om oprettelse af et almindeligt JavaScript-objekt og angivelse af relevante egenskaber. Følgende kode viser to gyldige metoder til at definere et JavaScript-objekt med egenskaber og værdier. I dette eksempel bruges valgte egenskaber fra kontaktobjektet defineret i contact EntityType.

var contact = new Object();
contact.firstname = "John";
contact.lastname = "Smith";
contact.accountrolecode = 2; //Employee
contact.creditonhold = false; //Number value works here too. 0 is false and 1 is true
contact.birthdate = new Date(1980, 11, 2);
contact["parentcustomerid_account@odata.bind"] = "/accounts(f3a11f36-cd9b-47c1-8c44-e65b961257ed)"

var contact = {
 firstname: "John",
 lastname: "Smith",
 accountrolecode: 2,//Employee
 creditonhold: false,
 birthdate: new Date(1980, 11, 2),
 "parentcustomerid_account@odata.bind": "/accounts(f3a11f36-cd9b-47c1-8c44-e65b961257ed)"
};

Uanset hvordan disse objekter defineres, når du bruger JSON.stringify, konverteres de begge til den samme JSON-streng.

    {
     "firstname": "John",
     "lastname": "Smith",
     "accountrolecode": 2,
     "creditonhold": false,
     "birthdate": "1980-12-02T08:00:00.000Z",
     "parentcustomerid_account@odata.bind": "/accounts(f3a11f36-cd9b-47c1-8c44-e65b961257ed)"
    }

Der er tidspunkter, når du skal definere en egenskab, der ikke følger almindelige retningslinjer for navngivning af JavaScript. For eksempel når du angiver værdien for en navigationsegenskabs enkeltværdi ved oprettelse af et objekt, skal du tilføje @odata.bind til navnet på egenskaben og angive værdien til en URL-adresse, der svarer til det relaterede objekt. I dette tilfælde skal du angive egenskaben i et format for parentesformat, som vist i ovenstående eksempel.

Du ser ikke objektegenskaber til et objekt, undtagen når du arbejder med metadataobjekter. Med metadataobjekter skal du jævnligt angive egenskaber, der er komplekse type eller optællingsværdier. Men det er ikke almindeligt med almindelig forretningsobjekter.

Når du opretter relaterede objekter kan du angive værdien for en navigationsegenskab med gruppeværdi b ved hjælp af en Array, men dette er en forholdsvis specialiseret operation.Flere oplysninger:Oprette relaterede objekter på én gang

Objekttypeegenskaber

Når du bogfører et objekt til en handling, hvor parametertypen repræsenterer en basistype for objektet, som crmbaseentity EntityType eller activitypointer EntityType, kan det være nødvendigt, at du medtager @odata.type-egenskaben med det fulde navn på objekttypen som værdien. Da letter EntityType f.eks. arver fra activitypointer, skal du eventuelt udtrykkeligt angive typen af objektet ved hjælp af følgende egenskab og værdi:"@odata.type": "Microsoft.Dynamics.CRM.letter".

Sende data til opdateringstransaktioner

Når du opdaterer objekter, er det vigtigt, at du kun angiver egenskabsværdier for de egenskaber, du vil opdatere. Du bør ikke hente et objekt, opdatere egenskaberne for den hentede forekomst og derefter bruge denne forekomst i en opdateringshandling. I stedet skal du oprette et nyt objekt og angive nye egenskaber kun for de egenskaber, du vil opdatere.

Hvis du blot kopierer alle egenskaberne for et objekt, der er hentet, og opdaterer der ved hjælp af PATCH, betragtes hver af de egenskaber, du sender, som en opdatering, selvom værdien er den samme som den aktuelle værdi. Hvis du har overvågning er aktiveret for objektet og attributten, indikerer den, at dataene ændres, selvom der ikke er nogen faktisk ændring i værdien.Flere oplysninger:Grundlæggende opdatering

Fortolke JSON-returneret

Selvom oprettelseshandlingen, der bruges i det foregående eksempel, ikke returnerer JSON-data, vil de fleste handlinger, der bruger GET, returnere JSON. For de fleste typer data, der returneres, kan konvertering af JSON i JavaScript opnås ved hjælp af følgende kodelinje.

var data = JSON.parse(this.response)

Data, der indeholder datoer, er dog et problem, da datoer er sendt som en streng, for eksempel 2015-10-25T17:23:55Z. For at konvertere det til et JavaScriptDate-objekt, skal du bruge reviver-parameteren for JSON.parse-funktionen. Følgende er et eksempel på en funktion, der kan bruges til at fortolke datoer.

function dateReviver(key, value) {
  var a;
  if (typeof value === 'string') {
   a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
   if (a) {
    return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6]));
   }
  }
  return value;
 };

Hvis du vil anvende denne funktion, skal du bare den som en parameter, som vist her.

var data = JSON.parse(this.response,dateReviver)

Oprette en funktion, der kan genbruges, ved hjælp af tilbagekald

Når du har koden til at udføre en bestemt handling, skal du bruge den igen i stedet for at skrive den samme kode igen og igen. Det næste trin er at oprette et JavaScript-bibliotek, der indeholder en funktion til at udføre handlingen med de tilgængelige indstillinger. I dette tilfælde er der kun to variabler for oprettelseshandlingen: navnet på objektsættet og JSON-definition af objektet, der skal oprettes. I stedet for at skrive koden vist tidligere, kan den samme operation indeholdes i en funktion, der kun kræver et par linjer kode at bruge.

Asynkrone handlinger med JavaScript har traditionelt anvendt tilbagekaldsfunktioner som en måde at indsamle de returnerede værdier fra den asynkrone handling og fortsætte logikken i programmet. Ved at bruge koden til oprettelseshandlingen, som beskrevet tidligere, er målet her at gøre det muligt for den samme handling at blive udført ved hjælp af den følgende kode.

MyNameSpace.WebAPI.create("accounts",
{ name: "Sample account" },
function (accountUri) { console.log("Created account with URI: " + accountUri) },
function (error) { console.log(error.message); });

I dette eksempel repræsenterer MyNameSpace.WebAPI den bedste fremgangsmåde for at angive et entydigt navn til alle funktioner, du bruger.Flere oplysninger:Definer entydige navne for JavaScript-funktioner

Vi medtager funktioner for yderligere handlinger for dette bibliotek, så der er mulighed for at have private funktioner, der kan genbruges, til at understøtte operationer. Følgende kode viser et bibliotek, der demonstrerer dette og indeholder en MyNameSpace.WebAPI.create-funktion, der bruger tilbagekald.

"use strict";
var MyNameSpace = window.MyNameSpace || {};
MyNameSpace.WebAPI = MyNameSpace.WebAPI || {};
(function () {
 this.create = function (entitySetName, entity, successCallback, errorCallback) {
  var req = new XMLHttpRequest();
  req.open("POST", encodeURI(getWebAPIPath() + entitySetName), true);
  req.setRequestHeader("Accept", "application/json");
  req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
  req.setRequestHeader("OData-MaxVersion", "4.0");
  req.setRequestHeader("OData-Version", "4.0");
  req.onreadystatechange = function () {
   if (this.readyState == 4 /* complete */) {
    req.onreadystatechange = null;
    if (this.status == 204) {
     if (successCallback)
      successCallback(this.getResponseHeader("OData-EntityId"));
    }
    else {
     if (errorCallback)
      errorCallback(MyNameSpace.WebAPI.errorHandler(this.response));
    }
   }
  };
  req.send(JSON.stringify(entity));
 };

 //Internal supporting functions
 function getClientUrl() {
  //Get the organization URL
  if (typeof GetGlobalContext == "function" &&
      typeof GetGlobalContext().getClientUrl == "function") {
   return GetGlobalContext().getClientUrl();
  }
  else {
   //If GetGlobalContext is not defined check for Xrm.Page.context;
   if (typeof Xrm != "undefined" &&
       typeof Xrm.Page != "undefined" &&
       typeof Xrm.Page.context != "undefined" &&
       typeof Xrm.Page.context.getClientUrl == "function") {
    try {
     return Xrm.Page.context.getClientUrl();
    } catch (e) {
     throw new Error("Xrm.Page.context.getClientUrl is not available.");
    }
   }
   else { throw new Error("Context is not available."); }
  }
 }
 function getWebAPIPath() {
  return getClientUrl() + "/api/data/v8.1/";
 }

 // This function is called when an error callback parses the JSON response
 // It is a public function because the error callback occurs within the onreadystatechange 
 // event handler and an internal function would not be in scope.
 this.errorHandler = function (resp) {
  try {
   return JSON.parse(resp).error;
  } catch (e) {
   return new Error("Unexpected Error")
  }
 }

}).call(MyNameSpace.WebAPI);

Dette bibliotek demonstrerer den bedste fremgangsmåde til at definere en funktion i en selvudførende anonym funktion (også kendt som en selvstændig aktiveret anonym funktion eller straks-aktiveret anonym funktion) og knytte funktionen til MyNameSpace.WebAPI-navneområdet. Dette gør det muligt at definere interne funktioner, der ikke er tilgængelige i en anden kode. Alle funktioner, der er defineret som en del af this bliver offentlige, og alle funktioner i den anonyme funktion kan bruges af offentlige funktioner, men ikke lave kode uden for den anonyme funktion. Koden i funktionen kan ikke ændres af en anden kode på siden.

Navneområdet er defineret, så det ikke overskriver den anden kode, der bruger det samme navneområde, men overskriver alle funktioner med det samme navn, der er en del af dette navneområde. Du kan oprette separate biblioteker, der tilføjer yderligere offentlige funktioner til navneområdet, så længe de ikke har det samme navn.

MyNameSpace.WebAPI.create-funktionen sikrer følgende parametre:

Navn

Beskrivelse

entitySetName

Navnet på der objekt, der er angivet for typen objektet, du vil oprette.

entity

Et objekt med egenskaberne for det objekt, du vil oprette.

successCallback

Funktionen til at ringe, når objektet oprettes. URI'en for det oprettede objekt er sendt til denne funktion.

errorCallback

Funktionen til at ringe, når der opstår en fejl. Fejlen vil blive overført til denne funktion.

Den kode, der konfigurerer XMLHttpRequest-objektet er blevet ændret for at bruge disse parameterværdier og en ekstra intern hjælpefunktion getWebAPIPath , som finder den grundlæggende organisations-URI, og tilføjer URL-adressen for at matche rod-URI'en for Web API'en, så du ikke behøver at medtage den. URI'en for det oprettede objekt overføres til successCallback, hvis den er defineret. På samme måde bruges den offentlige errorHandler-funktion til at analysere eventuelle fejl, der returneres.errorHandler-funktionen skal være offentligt, fordi den ringes til hændelseshandleren for onreadystatechange-hændelsen, og den er ikke omfattet af navneområdet. Den skal ringes til ved hjælp af det fulde navn: MyNameSpace.WebAPI.errorHandler.

Oprette en funktion, der kan genbruges, ved hjælp af tilsagn

Mens tilbagekald traditionelt er blevet anvendt til asynkrone handlinger, mener mange udviklere, at de er lidt uoverskuelige og svære at læse og foretage fejlfinding af, fordi en række asynkrone handlinger bygger videre på hinanden for at oprette kode, der danner en "pyramide of doom", idet indrykning bevirker, at koden ved brug af anonyme funktioner flytter længere og længere til højre på siden. Selvom dette problem kan løses ved hjælp af navngivne funktioner i stedet for anonyme funktioner,sætter mange udviklere pris på de fordele, der tilbydes af tilsagn. Et Promise -objekt repræsenterer en handling, der ikke er fuldført endnu, men forventes at gennemføres i fremtiden.

Der er mange tredjepartsbiblioteker og JavaScript-strukturer, som byder på forskellige implementeringer af tilsagn.JQuery har en funktionsmåde, der er baseret på CommonJS Promises/A designet via Udskudt objekt og andre insisterer på overensstemmelse med Promises/A+-specifikationen. En forklaring på forskellene mellem disse implementeringer er uden for rammerne af dette emne. Formålet med dette afsnit er ganske enkelt at beskrive, hvordan en hjælpefunktion for Microsoft Dynamics 365-Web API'en ved hjælp af et indbygget XMLHttpRequest-objekt kan skrives til at bruge det indbyggede Promise objekt, der er implementeret i de fleste moderne browsere, der understøttes af Microsoft Dynamics 365. Følgende browsere har en indbygget installation af tilsagn: Google Chrome 32, Opera 19 Mozilla Firefox 29 Apple Safari 8 og Microsoft Edge.

Bemærk

Internet Explorer 11 implementerer ikke indbyggede tilsagn. For browsere, der ikke implementerer indbyggede tilsagn, skal du medtage et separat bibliotek, der kan levere en polyfill. En polyfill er en kode, der indeholder funktioner, som ikke leveres direkte af en browser. Der er flere polyfills eller biblioteker, der giver Internet Explorer 11 mulighed for at få tilsagn: es6-promise, q.js og bluebird.

Fordelen ved at bruge tilsagn kan påvises bedst ved et eksempel. Følgende kode bruger tilbagekaldsversionen af MyNameSpace.WebAPI.create til at oprette en konto og derefter tre opgaver, der er knyttet til den.

MyNameSpace.WebAPI.create("accounts",
 { name: "Sample account" },
 function (accountUri) {
  console.log("Created account with URI: " + accountUri);
  MyNameSpace.WebAPI.create("tasks",
   { subject: "Task 1", "regardingobjectid_account_task@odata.bind": accountUri },
   function () {
    MyNameSpace.WebAPI.create("tasks",
     { subject: "Task 2", "regardingobjectid_account_task@odata.bind": accountUri },
     function () {
      MyNameSpace.WebAPI.create("tasks",
       { subject: "Task 3", "regardingobjectid_account_task@odata.bind": accountUri },
       function () {
        //Finished creating three tasks
        console.log("Three tasks created");
       },
      function (error) { console.log(error.message); });
     },
     function (error) { console.log(error.message); });
   },
  function (error) { console.log(error.message); });
 },
function (error) { console.log(error.message); });

I dette eksempel skal du ignorere det faktum, at disse poster blev oprettet med en enkelt handling ved hjælp af dybe Indsætninger.Flere oplysninger:Oprette relaterede objekter på én gang

Tilbagekaldskoden er udfordrende, fordi det ender midt i kodeblokken. I mellemtiden kan du med tilsagn oprette de samme poster med følgende kode.

var accountUri;
MyNameSpace.WebAPI.create("accounts", { name: "Sample account" })
.then(function (aUri) {
 accountUri = aUri;
 console.log("Created account with URI: " + accountUri);
})
.then(function () {
 return MyNameSpace.WebAPI.create("tasks", { subject: "Task 1", "regardingobjectid_account_task@odata.bind": accountUri });
})
.then(function () {
 return MyNameSpace.WebAPI.create("tasks", { subject: "Task 2", "regardingobjectid_account_task@odata.bind": accountUri });
})
.then(function () {
 return MyNameSpace.WebAPI.create("tasks", { subject: "Task 3", "regardingobjectid_account_task@odata.bind": accountUri });
})
.catch(function (error) { console.log(error.message); });

Ved at bruge tilsagn bevares kodestrømmen og giver mulighed for at fange eventuelle fejl, der opstår i en enkelt fangst-funktion.

Konvertering af funktionen med tilbagekald for at bruge tilsagn er et spørgsmål om at fjerne tilbagekaldsparametre og returnerer et lidt ændret XMLHttpRequest, som vist i følgende kodeeksempel.

return new Promise(function (resolve, reject) {
 var req = new XMLHttpRequest();
 req.open("POST", encodeURI(getWebAPIPath() + entitySetName), true);
 req.setRequestHeader("Accept", "application/json");
 req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
 req.setRequestHeader("OData-MaxVersion", "4.0");
 req.setRequestHeader("OData-Version", "4.0");
 req.onreadystatechange = function () {
 if (this.readyState == 4 /* complete */) {
  req.onreadystatechange = null;
  if (this.status == 204) {
  resolve(req.getResponseHeader("OData-EntityId"));
  }
  else {
  reject(MyNameSpace.WebAPI.errorHandler(req.response));
  }
 }
 };
 req.send(JSON.stringify(entity));
});

Ud over at fjerne tilbagekaldsparametrene er XMLHttpRequest inkluderet i Promise og i stedet for at overføre resultater eller fejl til vellykkede eller fejltilbagekald, overføres de til resolve- eller reject-parametre. Følgende kode repræsenterer hele JavaScript-bibliotek, der indeholder MyNameSpace.WebAPI.create-funktionen. Alt, hvad der er tilbage at gøre er at tilføje Web API-handlinger, der kan genbruges, ved hjælp af det samme mønster.

"use strict";
var MyNameSpace = window.MyNameSpace || {};
MyNameSpace.WebAPI = MyNameSpace.WebAPI || {};
(function () {
 /** @description Create a new entity
  * @param {string} entitySetName The name of the entity set for the type of entity you want to create.
  * @param {object} entity An object with the properties for the entity you want to create.
  */
 this.create = function (entitySetName, entity) {
  /// <summary>Create a new entity</summary>
  /// <param name="entitySetName" type="String">The name of the entity set for the entity you want to create.</param>
  /// <param name="entity" type="Object">An object with the properties for the entity you want to create.</param>       
  if (!isString(entitySetName)) {
   throw new Error("MyNameSpace.WebAPI.create entitySetName parameter must be a string.");
  }
  if (isNullOrUndefined(entity)) {
   throw new Error("MyNameSpace.WebAPI.create entity parameter must not be null or undefined.");
  }

  return new Promise(function (resolve, reject) {
   var req = new XMLHttpRequest();
   req.open("POST", encodeURI(getWebAPIPath() + entitySetName), true);
   req.setRequestHeader("Accept", "application/json");
   req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
   req.setRequestHeader("OData-MaxVersion", "4.0");
   req.setRequestHeader("OData-Version", "4.0");
   req.onreadystatechange = function () {
    if (this.readyState == 4 /* complete */) {
     req.onreadystatechange = null;
     if (this.status == 204) {
      resolve(req.getResponseHeader("OData-EntityId"));
     }
     else {
      reject(MyNameSpace.WebAPI.errorHandler(req.response));
     }
    }
   };
   req.send(JSON.stringify(entity));
  });

 };

 //Internal supporting functions
 function getClientUrl() {
  //Get the organization URL
  if (typeof GetGlobalContext == "function" &&
      typeof GetGlobalContext().getClientUrl == "function") {
   return GetGlobalContext().getClientUrl();
  }
  else {
   //If GetGlobalContext is not defined check for Xrm.Page.context;
   if (typeof Xrm != "undefined" &&
       typeof Xrm.Page != "undefined" &&
       typeof Xrm.Page.context != "undefined" &&
       typeof Xrm.Page.context.getClientUrl == "function") {
    try {
     return Xrm.Page.context.getClientUrl();
    } catch (e) {
     throw new Error("Xrm.Page.context.getClientUrl is not available.");
    }
   }
   else { throw new Error("Context is not available."); }
  }
 }
 function getWebAPIPath() {
  return getClientUrl() + "/api/data/v8.1/";
 }

 //Internal validation functions
 function isString(obj) {
  if (typeof obj === "string") {
   return true;
  }
  return false;

 }
 function isNull(obj) {
  if (obj === null)
  { return true; }
  return false;
 }
 function isUndefined(obj) {
  if (typeof obj === "undefined") {
   return true;
  }
  return false;
 }
 function isFunction(obj) {
  if (typeof obj === "function") {
   return true;
  }
  return false;
 }
 function isNullOrUndefined(obj) {
  if (isNull(obj) || isUndefined(obj)) {
   return true;
  }
  return false;
 }
 function isFunctionOrNull(obj) {
  if (isNull(obj))
  { return true; }
  if (isFunction(obj))
  { return true; }
  return false;
 }

 // This function is called when an error callback parses the JSON response.
 // It is a public function because the error callback occurs in the onreadystatechange 
 // event handler and an internal function wouldn’t be in scope.
 this.errorHandler = function (resp) {
  try {
   return JSON.parse(resp).error;
  } catch (e) {
   return new Error("Unexpected Error")
  }
 }

}).call(MyNameSpace.WebAPI);

Se også

Brug Microsoft Dynamics 365 Web API
Arbejde med Dynamics 365-data ved hjælp af webressourcer
Udføre operationer ved hjælp af web-API
Web API-eksempler (JavaScript på klientsiden)
Bruge OAuth med Cross-Origin Resource Sharing til at oprette forbindelse til et enkelt side-program til Microsoft Dynamics 365

Microsoft Dynamics 365

© 2017 Microsoft. Alle rettigheder forbeholdes. Ophavsret