Operazioni preliminari dell'API Web di Microsoft Dynamics 365 (JavaScript lato client)

 

Data di pubblicazione: gennaio 2017

Si applica a: Dynamics 365 (online), Dynamics 365 (on-premises), Dynamics CRM 2016, Dynamics CRM Online

Nelle risorse Web HTML, negli script dei moduli o nei comandi della barra multifunzione puoi utilizzare JavaScript per eseguire operazioni su dati Microsoft Dynamics 365 utilizzando la Web API introdotta con Microsoft Dynamics 365 (online e locale).

La Web API è particolarmente semplice da utilizzare con le risorse Web e JavaScript perché i dati JSON inviati e ricevuti vengono facilmente convertiti in oggetti JavaScript. Nondimeno, la maggior parte degli sviluppatori desidererà creare o utilizzare una libreria JavaScript helper per riutilizzare di codice e per mantenere il proprio codice di regole business separato dal codice per accedere ai dati. In questo argomento viene descritto come utilizzare l'oggetto XMLHttpRequest per eseguire operazioni con JavaScript nonché le opportunità per creare librerie JavaScript riutilizzabili che forniscono funzioni che funzionano con la Web API.

In questo argomento

Aree in cui puoi utilizzare JavaScript lato client

Informazioni su XMLHttpRequest

Uso di XMLHttpRequest

Composizione di dati JSON da inviare

Analisi dei dati JSON restituiti

Creare una funzione riutilizzabile utilizzando i callback

Creare una funzione riutilizzabile utilizzando le promesse

Aree in cui puoi utilizzare JavaScript lato client

Esistono due aree in cui puoi utilizzare JavaScript lato client per accedere a Microsoft Dynamics 365 mediante l'API Web:

  • Risorse Web JavaScript
    Codice JavaScript incluso in una risorsa Web JavaScript in esecuzione nel contesto di una risorsa Web HTML, script di moduli o comandi della barra multifunzione.

    Quando utilizzi le risorse Web JavaScript in Microsoft Dynamics 365 non è necessario che l'autenticazione delle risorse Web faccia parte dell'applicazione che l'utente ha già autenticato. Nella parte restante di questo argomento verrà trattato questo scenario.Ulteriori informazioni:Risorse Web per Microsoft Dynamics 365,Risorse Web per script (JScript), Utilizzare JavaScript con Microsoft Dynamics 365 e Librerie JavaScript per Microsoft Dynamics 365.

  • Applicazioni su singola pagina
    CodiceJavaScript in una libreria JavaScript da un'altra applicazione in esecuzione in un browser e autenticazione a Microsoft Dynamics 365 mediante la condivisione di risorse tra origini (CORS). Questo modello viene in genere utilizzato per le applicazioni su singola pagina.

    Quando si utilizza JavaScript in un'applicazione su singola pagina puoi usare la libreria adal.js per consentire all'utente di eseguire l'autenticazione e l'accesso ai dati di Microsoft Dynamics 365 in una pagina ospitata in un dominio diverso. La maggior parte delle informazioni in questo argomento si applica a questo scenario ma devi anche integrare un'intestazione di autorizzazione in una richiesta contenente un token di autenticazione. Per ulteriori informazioni, vedere Utilizzare OAuth con la condivisione di risorse tra origini per connettere un'applicazione su singola pagina a Microsoft Dynamics 365

Informazioni su XMLHttpRequest

Quando usi la Web API verrà utilizzato un oggetto XMLHttpRequest.XMLHttpRequest (XHR) è un oggetto nativo trovato in tutti i browser moderni e consente tecniche AJAX affinché le pagine Web siano dinamiche. Sebbene il nome dell'oggetto contenga "XML", tutti le richieste che utilizzano la Web API utilizzeranno il codice JSON anziché XML.

XMLHttpRequest utilizzato da framework JavaScript

I frameworkJavaScript quali jQuery spesso racchiudono l'oggetto XMLHttpRequest sottostante in una funzione (ad esempio $.ajax) perché in precedenza non tutti i browser fornivano un oggetto XMLHttpRequest nativo in modo standard e anche per semplificare l'utilizzo. Ora che i browser moderni hanno un'implementazione XMLHttpRequest standard, non è necessaria una libreria separata per attenuare le differenze. Eppure molti sviluppatori continuano a basarsi sui framework JavaScript per richiedere le risorse server. Anche se è accettabile utilizzare jQuery e altri framework JavaScript nelle risorse Web HTML o nelle applicazioni su singola pagina, è consigliabile evitarli negli script di moduli o nei comandi della barra multifunzione. Con le diverse soluzioni che possono essere installate per un'organizzazione, ognuna potenzialmente con versioni diverse di un framework JavaScript, soprattutto jQuery, potrebbero verificarsi risultati imprevisti a meno che tutti eseguano passaggi per evitare conflitti. Se esegui richieste della Web API in script di moduli o comandi della barra multifunzione, è consigliabile usare direttamente XMLHttpRequest e non accettare una dipendenza da jQuery.Ulteriori informazioni:Utilizzare jQuery

In questo argomento viene descritto come utilizzare direttamente l'oggetto XMLHttpRequest nativo, ma gli stessi concetti si applicano all'utilizzo di jQuery o altri framework JavaScript eseguiti in un browser poiché tutti utilizzano XMLHttpRequest. È possibile utilizzare una libreria che utilizza XHR direttamente in un browser con qualsiasi framework JavaScript.

Uso di XMLHttpRequest

Di seguito è un esempio molto semplice che mostra come creare un'entità account usando la Web API e l'oggetto XMLHttpRequest. In questo esempio, solo la variabile clientURL non è definita.

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" }));

Le sezioni seguenti descrivono cosa fa il codice.

Aprire XMLHttpRequest

Dopo aver inizializzato l'oggetto XMLHttpRequest, è necessario aprirlo prima di poter impostare le proprietà o inviarlo. I parametri del metodo open sono un metodo di richiesta HTTP, un URL e un parametro boolean per indicare se l'operazione deve essere eseguita in modalità asincrona. È consigliabile scegliere sempre di eseguire le operazioni in modalità asincrona.Ulteriori informazioni:Utilizzare i metodi di accesso ai dati asincroni

In questo esempio, perché verrà creata un'entità account, è necessario impostare l'URL in modo che corrisponda al percorso del set di entità per il account EntityType. L'URL completo in questo esempio è clientURL + "/api/data/v8.1/accounts e la variabile clientURL deve essere impostata sull'URL radice dell'applicazione Microsoft Dynamics 365. Per le risorse Web che hanno accesso all'oggetto contesto, la funzione getClientUrl cui è possibile accedere tramite l'oggetto contesto lato client disponibile usando la Funzione GetGlobalContext in una risorsa Web HTML oppure tramite l'oggetto Xrm.Page.context in uno script di modulo o comando della barra multifunzione. Dovresti usare la funzione encodeURI in ogni URL inviato al servizio per assicurarti che non includa caratteri non sicuri.

Poiché questa funzione crea un'entità, il metodo di richiesta HTTP è POST come descritto in Creare un'entità utilizzando l'API Web.

Il metodo XMLHttpRequestopen consente inoltre di specificare un nome utente e una password. Non è necessario specificare un valore per questi parametri con le risorse Web perché l'utente è già autenticato. Per le applicazioni su singola pagina, l'autenticazione è gestita tramite un token anziché i parametri.

Impostare le intestazioni e il gestore eventi

Dopo aver aperto XMLHttpRequest è possibile applicare un certo numero di intestazioni di richiesta utilizzando il metodo setRequestHeader. In genere dovresti usare le intestazioni illustrate qui con alcune variazioni per tipi speciali di operazioni.Ulteriori informazioni:Intestazioni HTTP.

Prima di inviare la richiesta, è necessario includere un gestore eventi che rileva quando l'operazione è completata. Dopo l'invio della richiesta, questa passa attraverso vari stati prima che la risposta venga restituita. Per acquisire il momento del completamento di XMLHttpRequest, è necessario impostare un gestore eventi sulla proprietà onreadystatechange per rilevare quando la proprietà readystate è uguale a 4, che indica il completamento. A quel punto è possibile esaminare la proprietà status.

Nota

Dopo il completamento di XMLHttpRequest, è consigliabile impostare la proprietà onreadystatechange su null per evitare potenziali problemi di perdita di memoria.

Nella funzione anonima che è il gestore eventi, dopo aver verificato il completamento, è possibile esaminare la proprietà status per determinare se l'operazione è riuscita. In questo caso, il valore di stato previsto è 204 No Content perché non è previsto nessun contenuto nel corpo della risposta da un'operazione di creazione. L'URI per l'account creato è nell'intestazione OData-EntityId ed è accessibile utilizzando il metodo getResponseHeader.

Se questa fosse un'operazione diversa, che prevede la restituzione di dati nella risposta, avrebbe un valore 200 OKstatus e la funzione userebbe JSON.parse nella risposta XMLHttpRequest per convertire la risposta JSON in un oggetto JavaScript a cui il codice potrebbe accedere.Ulteriori informazioni:Analisi dei dati JSON restituiti

Se lo stato non è il valore previsto, è un errore e un oggetto errore viene restituito con le proprietà descritte in Analizzare gli errori dalla risposta. In questo esempio viene utilizzato JSON.parse per convertire la proprietà XMLHttpRequestresponse in un oggetto JavaScript in modo da poter accedere alla proprietà message.

Inviare XMLHttpRequest

Infine, utilizzare il metodo XMLHttpRequestsend per inviare la richiesta, inclusi tutti i dati JSON necessari. Utilizzare JSON.stringify per convertire gli oggetti JavaScript in stringhe JSON che è possibile includere nel corpo della richiesta all'invio.

Composizione di dati JSON da inviare

Nell'esempio precedente, l'entità account viene creata utilizzando solo un singolo set di proprietà. Per determinare quali proprietà sono disponibili per un'entità devi esaminare il Documento di metadati CSDL, documentazione generata da quel documento o codice generato tramite quel documento. Per le entità aziendali di sistema incluse in tutte le organizzazioni Microsoft Dynamics 365, puoi fare riferimento a Web API EntityType Reference. I nomi delle proprietà sono minuscoli e accettano tipi di dati semplici che corrispondono ai tipi JavaScript seguenti: Boolean, Number, String, Array, Object e Date.

Nota

L'unica eccezione all'uso dei tipi di dati semplici è BooleanManagedProperty ComplexType che viene utilizzato per le entità che archiviano i dati che riconoscono la soluzione, come risorse Web, modelli, report, ruoli, savedqueries e per le entità di metadati. Questa proprietà non è mai utilizzata per le entità che archiviano i dati aziendali. Le entità di metadati usano molti tipi complessi e seguono regole diverse. Per ulteriori informazioni, vedere Utilizzare l'API Web con i metadati di Dynamics 365.

Comporre dati da inviare in una richiesta in genere consiste semplicemente nella creazione di un normale oggetto JavaScript e nell'impostazione delle proprietà appropriate. Il codice seguente mostra due metodi validi per la definizione di un oggetto JavaScript con proprietà e valori. In questo esempio vengono utilizzate proprietà selezionate dell'entità contatto definita in 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)"
};

Indipendentemente da come questi oggetti vengono definiti, dopo aver utilizzato JSON.stringify, verranno entrambi convertiti nella stessa stringa JSON.

    {
     "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)"
    }

Vi sono situazioni in cui è necessario definire una proprietà che non segue le normali linee guida di denominazione per JavaScript. Ad esempio, quando si imposta il valore di una proprietà di navigazione a valore singolo quando si crea un'entità, è necessario aggiungere @odata.bind al nome della proprietà e impostare il valore su un URL che corrisponde all'entità correlata. In questo caso, devi definire la proprietà in uno stile di notazione tra parentesi come illustrato nell'esempio precedente.

Tranne quando si lavora con entità metadati, non imposterai le proprietà di un'entità su un oggetto. Con le entità metadati è spesso necessario impostare proprietà che sono valori di tipo o di enumerazione complessi. Ma ciò non è comune con le entità aziendali normali.

Quando si creano entità correlate è possibile impostare il valore di una proprietà di navigazione con valori di raccolta utilizzando Array, tuttavia questa è un'operazione piuttosto sofisticata.Ulteriori informazioni:Creare entità correlate con un'unica operazione

Proprietà dei tipi di entità

Quando si inserisce un'entità in un'azione in cui il tipo di parametro rappresenta un tipo di base per l'entità, ad esempio crmbaseentity EntityType o activitypointer EntityType, potrebbe essere necessario includere la proprietà @odata.type con il nome completo del tipo di entità come valore. Ad esempio, poiché letter EntityType eredita da activitypointer, può essere necessario indicare in modo esplicito il tipo di entità usando i seguenti proprietà e valore:"@odata.type": "Microsoft.Dynamics.CRM.letter".

Invio di dati per le operazioni di aggiornamento

Quando si aggiornano le entità, è importante impostare solo i valori delle proprietà che si intende aggiornare. Non è opportuno recuperare un'entità, aggiornare le proprietà dell'istanza recuperata e quindi utilizzare tale istanza in un'operazione di aggiornamento. Invece, è necessario creare un nuovo oggetto e impostare nuove proprietà solo per le proprietà da aggiornare.

Se si effettua semplicemente la copia di tutte le proprietà di un'entità recuperata e la si aggiorna utilizzando PATCH, ogni proprietà inviata sarà considerata un aggiornamento, anche il valore è lo stesso del valore corrente. Se è attivato il controllo per l'entità e l'attributo, indicherà che i dati sono stati modificati quando non c'è stata nessuna effettiva modifica nel valore.Ulteriori informazioni:Aggiornamento di base

Analisi dei dati JSON restituiti

Sebbene l'operazione di creazione utilizzata nell'esempio precedente non restituisca dati JSON, la maggior parte delle operazioni con GET restituiscono JSON. Per la maggior parte dei tipi di dati restituiti, la conversione di JSON in JavaScript può essere ottenuta utilizzando la riga di codice seguente.

var data = JSON.parse(this.response)

Tuttavia, i dati che includono date costituiscono un problema perché le date sono passate come stringa, ad esempio 2015-10-25T17:23:55Z. Per convertire questo codice in un oggetto JavaScriptDate è necessario utilizzare il parametro reviver per la funzione JSON.parse. Di seguito è un esempio di una funzione utilizzabile per analizzare le date.

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;
 };

Per applicare questa funzione includila come parametro, come illustrato di seguito.

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

Creare una funzione riutilizzabile utilizzando i callback

Quando disponi di codice per eseguire una specifica operazione, vorrai riutilizzarlo anziché riscriverlo ogni volta che serve. Il passaggio successivo è creare una libreria JavaScript contenente una funzione per eseguire l'operazione con tutte le opzioni disponibili. In questo caso ci sono solo due variabili per l'operazione di creazione: il nome del set di entità e la definizione JSON dell'entità da creare. Anziché scrivere tutto il codice indicato in precedenza, la stessa operazione può essere contenuta in una funzione di poche righe.

Le operazioni asincrone con JavaScript hanno tradizionalmente impiegato le funzioni di callback come modo per acquisire i valori restituiti dall'operazione asincrona e continuare con la logica del programma. Usando il codice per l'operazione di creazione descritta in precedenza, l'obiettivo in questo caso è consentire la stessa operazione usando solo il codice seguente.

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

In questo esempio, MyNameSpace.WebAPI rappresenta la procedura consigliata per fornire un nome univoco a qualsiasi funzione utilizzata.Ulteriori informazioni:Definire nomi univoci per le proprie funzioni JavaScript

Per questa libreria è prevista l'inclusione di funzioni per operazioni aggiuntive, quindi c'è un'opportunità di disporre di funzioni private riutilizzabili per supportare le operazioni. Il codice seguente illustra una libreria che dimostra ciò e include una funzione MyNameSpace.WebAPI.create utilizzando dei callback.

"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);

Questa libreria illustra la procedura consigliata di definire una funzione in una funzione anonima a esecuzione automatica (detta anche funzione anonima autorichiamata o funzione anonima immediatamente richiamata) e associare la funzione allo spazio dei nomi MyNameSpace.WebAPI. Questo consente di definire funzioni interne che non sono accessibili da altro codice. Qualsiasi funzione definita come parte di this sarà pubblica e qualsiasi funzione nella funzione anonima può essere utilizzata dalle funzioni pubbliche ma non da codice esterno alla funzione anonima. Il codice nella funzione non può essere modificato da altro codice nella pagina.

Lo spazio dei nomi è definito in modo da non sovrascrivere altro codice che utilizza lo stesso spazio dei nomi, ma sovrascriverà le funzioni con lo stesso nome che fanno parte di questo spazio dei nomi. È possibile creare librerie separate che aggiungono funzioni pubbliche aggiuntive allo spazio dei nomi a condizione che non abbiano lo stesso nome.

La funzione MyNameSpace.WebAPI.create fornisce i parametri seguenti:

Nome

Descrizione

entitySetName

Il nome del set di entità per il tipo di entità che si desidera creare.

entity

Oggetto con le proprietà dell'entità che si desidera creare.

successCallback

La funzione da chiamare quando l'entità viene creata. L'Uri dell'entità creata viene passato a questa funzione.

errorCallback

La funzione da chiamare quando esiste un errore. L'errore verrà passato a questa funzione.

Il codice che configura l'oggetto XMLHttpRequest è stato modificato per utilizzare questi valori dei parametri e anche una funzione helper interna aggiuntiva getWebAPIPath che troverà l'URI dell'organizzazione di base e aggiungerà l'URL in modo che corrisponda all'URI radice per la Web API, in modo che non sia necessario includerlo. L'URI per l'entità creata viene passato a successCallback se è definito. Analogamente la funzione errorHandler pubblica viene usata per analizzare qualsiasi messaggio di errore che viene restituito. La funzione errorHandler deve essere pubblica perché viene chiamata nel gestore eventi per l'evento onreadystatechange e ciò non è incluso nell'ambito dello spazio dei nomi. Deve essere chiamata utilizzando il nome completo: MyNameSpace.WebAPI.errorHandler.

Creare una funzione riutilizzabile utilizzando le promesse

Anche se i callback sono stati tradizionalmente utilizzati per le operazioni asincrone, molti sviluppatori li ritengono piuttosto difficili da gestire, da leggere e da sottoporre a debug perché una serie di operazioni asincrone viene compilata a livelli sovrapposti per creare codice che forma una "piramide di sventura", dal momento che il rientro provoca lo spostamento del codice, che utilizza le funzioni anonime, sempre più verso il lato destro della pagina. Sebbene questo problema possa essere risolto tramite funzioni denominate anziché anonime, molti sviluppatori apprezzano i vantaggi offerti dalle promesse. Un oggetto Promise rappresenta un'operazione che non è ancora completata, ma di cui si prevede il completamento nel futuro.

Esistono numerose librerie e framework JavaScript di terze parti che offrono diverse implementazioni di promesse.JQuery ha offerto un comportamento basato sulla progettazione CommonJS Promises/A tramite l'oggetto Deferred e altri insistono sulla conformità alla specifica Promises/A+. Una spiegazione delle differenze tra queste implementazioni non rientra nell'ambito di questo argomento. L'obiettivo della sezione è semplicemente di evidenziare come una funzione helper per la Web API di Microsoft Dynamics 365 che utilizza un oggetto XMLHttpRequest nativo può essere scritta per utilizzare l'oggetto Promise nativo implementato nella maggior parte dei browser moderni supportati da Microsoft Dynamics 365. I seguenti browser dispongono di un'implementazione nativa di promesse: Google Chrome 32, Opera 19, Mozilla Firefox 29, Apple Safari 8 e Microsoft Edge.

Nota

Internet Explorer 11 non implementa le promesse native. Per i browser che non implementano promesse native, è necessario includere una libreria separata per fornire un polyfill. Il polyfill è un codice che offre funzionalità non disponibili in modo nativo in un browser. Esistono diversi polyfill o librerie che permetteranno a Internet Explorer 11 di utilizzare le promesse: es6-promise, q.js e bluebird.

Il vantaggio di utilizzare le promesse può essere illustrato al meglio con un esempio. Il codice seguente utilizza la versione di callback di MyNameSpace.WebAPI.create per creare un account e quindi tre attività associate.

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); });

Ai fini di questo esempio, ignorare il fatto che tutti questi record possono essere creati in un'unica operazione di deep insert.Ulteriori informazioni:Creare entità correlate con un'unica operazione

Il codice di callback è problematico perché termina nel mezzo del blocco di codice. Allo stesso tempo, con le promesse è possibile creare gli stessi record con il codice seguente.

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); });

Utilizzare le promesse conserva il flusso del codice e consente di intercettare gli errori che si verificano con un'unica funzione catch.

Convertire la funzione con callback in modo da usare le promesse è una questione di rimozione dei parametri di callback e restituire un oggetto XMLHttpRequest leggermente modificato, come illustrato nel seguente esempio di codice.

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));
});

Oltre a rimuovere i parametri di callback, XMLHttpRequest viene incluso nell'oggetto Promise e anziché passare ai callback di operazione riuscita o di errore, i risultati o gli errori vengono passati ai parametri resolve o reject. Il codice seguente rappresenta l'intera libreria JavaScript contenente la funzione MyNameSpace.WebAPI.create. Quello che rimane da fare è l'aggiunta di ulteriori operazioni Web API riutilizzabili utilizzando lo stesso modello.

"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);

Vedere anche

Utilizzare l'API Web di Microsoft Dynamics 365
Lavorare con i dati Dynamics 365 utilizzando le risorse Web
Eseguire operazioni tramite l'API Web
Esempi di API Web (JavaScript lato client)
Utilizzare OAuth con la condivisione di risorse tra origini per connettere un'applicazione su singola pagina a Microsoft Dynamics 365

Microsoft Dynamics 365

© 2017 Microsoft. Tutti i diritti sono riservati. Copyright