Share via


Se familiariser avec l'API Web (JavaScript côté client) Microsoft Dynamics 365

 

Date de publication : janvier 2017

S’applique à : Dynamics 365 (online), Dynamics 365 (on-premises), Dynamics CRM 2016, Dynamics CRM Online

Dans les ressources Web HTML, les scripts de formulaire ou les commandes du ruban, vous pouvez utiliser JavaScript pour exécuter des opérations sur les données Microsoft Dynamics 365 à l'aide de l'Web API fournie avec Microsoft Dynamics 365 (Online et local).

L'Web API est particulièrement facile à utiliser avec JavaScript et les ressources Web, car les données JSON envoyées et reçues avec celle-ci sont facilement converties en objets JavaScript. Pourtant, la plupart des développeurs souhaitent créer ou utiliser une bibliothèque JavaScript d'assistance pour tirer parti de la réutilisation du code et dissocier leur code de logique métier de leur code d'accès aux données. Cette rubrique décrit comment utiliser l'objet XMLHttpRequest pour exécuter des opérations avec JavaScript, ainsi que les opportunités pour créer des bibliothèques JavaScript réutilisables qui fournissent des fonctions à utiliser avec l'Web API.

Contenu de la rubrique

Zones dans lesquelles vous pouvez utiliser JavaScript côté client

Description de XMLHttpRequest

Utilisation de XmlHttpRequest

Composition des données JSON à envoyer

Analyse de JSON retournée

Créer une fonction réutilisable à l'aide de rappels

Créer une fonction réutilisable à l'aide des promesses

Zones dans lesquelles vous pouvez utiliser JavaScript côté client

Il existe deux zones où vous pouvez utiliser JavaScript côté client pour accéder à Microsoft Dynamics 365 à l'aide de l'API Web :

  • Ressources Web JavaScript.
    Code JavaScript inclus dans une ressource Web JavaScript s'exécutant dans le contexte d'une ressource Web HTML, des scripts de formulaire ou des commandes du ruban.

    Lorsque vous utilisez des ressources Web JavaScript dans Microsoft Dynamics 365, inutile d'authentifier car les ressources Web font partie de l'application que l'utilisateur a déjà authentifiée. La suite de cette rubrique se concentre sur ce scénario.Pour plus d'informations :Ressources Web pour Microsoft Dynamics 365,Ressources Web de script (JScript), Utilisation de JavaScript avec Microsoft Dynamics 365, et Bibliothèques JavaScript pour Microsoft Dynamics 365.

  • Applications sur une seule page
    Code JavaScript dans une bibliothèque JavaScript provenant d'une autre application s'exécutant dans un navigateur et s'authentifiant dans Microsoft Dynamics 365 via le Partage des ressources cross-origin (CORS). Ce modèle est généralement utilisé pour des applications sur une seule page.

    Lorsque vous utilisez JavaScript dans une application sur une seule page (SPA), vous pouvez utiliser la bibliothèque adal.js pour permettre à l'utilisateur de s'authentifier et d'accéder aux données de Microsoft Dynamics 365 dans une page hébergée dans un autre domaine. La plupart des informations de cette rubrique s'appliquent à ce scénario, mais vous devez également intégrer un en-tête d'autorisation dans n'importe quelle demande contenant un jeton d'authentification. Pour plus d’informations, voir Utilisez OAuth avec le partage des ressources cross-origin pour connecter une application sur une seule page à Microsoft Dynamics 365

Description de XMLHttpRequest

Lorsque vous utilisez l'Web API, un objet XMLHttpRequest est utilisé.XMLHttpRequest (XHR) est un objet natif disponible dans tous les navigateurs modernes qui permet aux techniques AJAX de rendre les pages Web dynamiques. Bien que le nom de l'objet contienne « XML », toutes les demandes avec l'API Web utilisent JSON au lieu de XML.

XMLHttpRequest utilisé par les structures JavaScript

Les structures JavaScript comme jQuery enveloppent souvent l'objet XMLHttpRequest sous-jacent dans une fonction (telle que $.ajax), car auparavant tous les navigateurs ne fournissaient pas un objet XMLHttpRequest natif en standard, et également pour simplifier l'utilisation. Maintenant que les navigateurs modernes ont une implémentation XMLHttpRequest standard, une bibliothèque distincte n'est pas nécessaire pour atténuer ces différences. Pourtant, de nombreux développeurs continuent à utiliser les structures JavaScript pour demander des ressources du serveur. Bien qu'il soit possible d'utiliser jQuery et d'autres structures JavaScript dans les ressources Web HTML ou les SPA, nous vous déconseillons de les utiliser dans les scripts de formulaire ou les commandes du ruban. Avec les différentes solutions pouvant être installées pour une organisation, chacune incluant potentiellement différentes versions d'une structure JavaScript, en particulier jQuery, des résultats inattendus peuvent se produire sauf si des mesures sont prises pour éviter les conflits. Si vous effectuez des demandes dans les scripts de formulaire ou les commandes du ruban à l'aide de l'API Web, il est recommandé d'utiliser XMLHttpRequest directement sans créer de dépendance sur jQuery.Pour plus d'informations :Utiliser jQuery

Cette rubrique explique comment utiliser l'objet XMLHttpRequest natif directement, mais les mêmes concepts s'appliquent lorsque vous utilisez jQuery ou d'autres structures JavaScript qui s'exécutent dans un navigateur, car elles utilisent toutes XMLHttpRequest. Vous pouvez utiliser une bibliothèque qui utilise XHR directement dans un navigateur avec n'importe quelle structure JavaScript.

Utilisation de XmlHttpRequest

Vous trouverez ci-dessous un exemple très simple qui explique comment créer une entité de compte à l'aide de l'API Web et de l'objet XMLHttpRequest. Dans cet exemple, seule la variable clientURL n'est pas définie.

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

Les sections suivantes décrivent la fonction de ce code.

Ouvrir XMLHttpRequest

Après avoir initialisé l'objet XMLHttpRequest, vous devez l'ouvrir pour pouvoir définir ses propriétés ou l'envoyer. Les paramètres de la méthode open sont une méthode de demande HTTP, une URL et un paramètre boolean pour indiquer si l'opération doit être effectuée de manière asynchrone. Vous devez toujours choisir d'effectuer les opérations de manière asynchrone.Pour plus d'informations :Utiliser des méthodes d’accès aux données asynchrones

Dans cet exemple, comme nous créons une entité de compte, nous devons définir l'URL de manière à ce qu'elle corresponde au chemin d'accès de l'ensemble d'entités pour le account EntityType. L'URL complète dans cet exemple est clientURL + "/api/data/v8.1/accounts et la variable clientURL doit être définie sur l'URL racine de l'application Microsoft Dynamics 365. Pour les ressources Web qui ont accès à l'objet de contexte, la fonction getClientUrl qui est accessible via l'objet de contexte côté client disponible en utilisant la Fonction GetGlobalContext dans une ressource Web HTML ou l'objet Xrm.Page.context dans un script de formulaire ou une commande du ruban. Vous devez utiliser la fonction encodeURI sur une URL que vous envoyez au service pour vérifier qu'elle ne contient pas de caractères non sécurisés.

Comme cette fonction crée une entité, la méthode de demande HTTP est POST, comme décrit dans Créer une entité à l'aide de l'API Web.

La méthode XMLHttpRequestopen permet également de spécifier un nom d'utilisateur et un mot de passe. Il n'est pas nécessaire de spécifier une valeur pour ces paramètres avec les ressources Web car l'utilisateur est déjà authentifié. Pour les SPA, l'authentification est gérée via un jeton et non par ces paramètres.

Définir les en-têtes et le gestionnaire d'événements

Après avoir ouvert XMLHttpRequest, vous pouvez appliquer plusieurs en-têtes de demande à l'aide de la méthode setRequestHeader. Vous devez généralement utiliser les en-têtes décrits ici, avec quelques variations pour des types particuliers d'opérations.Pour plus d'informations :En-têtes HTTP.

Avant d'envoyer la demande, vous devez inclure un gestionnaire d'événements qui détecte si l'opération est terminée. Une fois la demande envoyée, elle passe par plusieurs états avant que la réponse soit retournée. Pour capturer le moment où XMLHttpRequest est terminé, vous devez définir un gestionnaire d'événements sur la propriété onreadystatechange pour détecter quand la propriété readystate est égale à 4, qui indique que l'opération est terminée. Vous pouvez alors examiner la propriété status.

Notes

Une fois XMLHttpRequest terminé, il est recommandé de définir la propriété onreadystatechange sur null pour éviter les problèmes potentiels de fuite de mémoire.

Dans la fonction anonyme de votre gestionnaire d'événements, après avoir vérifié que l'opération est terminée, vous pouvez examiner la propriété status pour déterminer si l'opération s'est correctement déroulée. Dans ce cas, la valeur de statut attendue est 204 No Content, car aucun contenu n'est attendu dans le corps de la réponse pour une opération de création. L'URI du compte créé se trouve dans l'en-tête OData-EntityId et est accessible à l'aide de la méthode getResponseHeader.

Si une opération différente était attendue pour retourner les données de la réponse, la valeur serait 200 OKstatus et la fonction utiliserait JSON.parse sur la réponse XMLHttpRequest pour convertir la réponse JSON en objet JavaScript auquel votre code pourrait accéder.Pour plus d'informations :Analyse de JSON retournée

Si le statut n'est pas la valeur attendue, une erreur s'est produite et un objet d'erreur est retourné avec les propriétés décrites dans Analyse des erreurs relatives à la réponse. Cet exemple utilise JSON.parse pour convertir la propriété XMLHttpRequestresponse en objet JavaScript afin que la propriété message soit accessible.

Envoyer XMLHttpRequest

Enfin, utilisez la méthode XMLHttpRequestsend pour envoyer la demande, y compris les données JSON requises. Utilisez JSON.stringify pour convertir des objets JavaScript en chaînes JSON pouvant être incluses dans le corps de la demande lors de son envoi.

Composition des données JSON à envoyer

Dans l'exemple précédent, l'entité de compte est créée avec un seul ensemble de propriétés. Pour déterminer les propriétés disponibles pour une entité, vous devez consulter le Document de métadonnées CSDL, la documentation générée à partir de ce document ou le code généré à l'aide de ce document. Pour les entités d'entreprise système incluses dans toutes les organisations Microsoft Dynamics 365, vous pouvez vous reporter à la Web API EntityType Reference. Les noms de propriété sont en minuscules et acceptent les types de données simples correspondant aux types JavaScript suivants : Boolean, Number, String, Array, Object et Date.

Notes

La seule exception à utiliser les types de données simples est le BooleanManagedProperty ComplexType qui est utilisé pour les entités qui stockent des données pouvant utiliser la solution telles que des ressources Web, des modèles, des rapports, des rôles, des requêtes enregistrées et dans les entités de métadonnées. Cette propriété n'est jamais utilisée pour les entités qui stockent des données d'entreprise. Les entités de métadonnées utilisent de nombreux types complexes et suivent plusieurs règles. Pour plus d'informations, voir Utiliser l'API Web avec les métadonnées Dynamics 365.

La composition des données à envoyer dans une demande consiste simplement à créer un objet JavaScript ordinaire et à définir les propriétés appropriées. Le code suivant présente deux méthodes valides pour définir un objet JavaScript avec des propriétés et des valeurs. Cet exemple utilise les propriétés sélectionnées à partir de l'entité de contact définie dans 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)"
};

Quelle que soit la façon dont ces objets sont définis, une fois que vous utilisez JSON.stringify, ils sont tous deux convertis dans la même chaîne 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)"
    }

Vous devez parfois définir une propriété qui ne respecte pas les règles d'attribution de noms de propriété ordinaires pour JavaScript. Par exemple, lorsque vous définissez la valeur d'une propriété de navigation à valeur unique en créant une entité, vous devez ajouter @odata.bind au nom de la propriété et définir la valeur sur une URL correspondant à l'entité associée. Dans ce cas, vous devez définir la propriété dans un style de notation entre crochets, comme illustré dans l'exemple précédent.

Vous ne définissez pas les propriétés d'entité sur un objet sauf si vous utilisez des entités de métadonnées. Avec les entités de métadonnées, vous devez souvent définir des propriétés qui sont des valeurs d'énumération ou de type complexes. Mais cela se produit rarement avec les entités métier ordinaires.

Lorsque vous créez des entités associées, vous pouvez définir la valeur d'une propriété de navigation à valeur de collection à l'aide d'un Array, mais il s'agit d'une opération assez spécialisée.Pour plus d'informations :Créer des entités associées en une opération

Propriétés de type d'entité

Lorsque vous publiez une entité sur une action dans laquelle le type de paramètre représente un type de base pour l'entité, par exemple crmbaseentity EntityType ou activitypointer EntityType, vous devrez peut-être inclure la propriété @odata.type avec le nom complet du type d'entité comme valeur. Par exemple, comme letter EntityType hérite de activitypointer, vous devrez peut-être définir explicitement le type d'entité à l'aide de la propriété et de la valeur suivantes :"@odata.type": "Microsoft.Dynamics.CRM.letter".

Envoi de données pour les opérations de mise à jour

Lorsque vous mettez à jour des entités, il est important de définir uniquement les valeurs des propriétés que vous prévoyez de mettre à jour. Vous ne devez pas récupérer une entité, mettre à jour les propriétés de l'instance récupérée et utiliser cette instance dans une opération de mise à jour. À la place, vous devez créer un objet et définir de nouvelles propriétés uniquement pour les propriétés que vous prévoyez de mettre à jour.

Si vous copiez simplement toutes les propriétés d'une entité récupérée et la mettez à jour à l'aide de PATCH, chacune des propriétés envoyées est considérée comme une mise à jour, même si la valeur est identique à la valeur actuelle. Si l'audit est activé pour l'entité et l'attribut, il indique que les données ont été modifiées lorsqu'il n'y avait aucun changement réel de valeur.Pour plus d'informations :Mise à jour de base

Analyse de JSON retournée

Bien que l'opération de création utilisée dans l'exemple précédent ne retourne pas de données JSON, la plupart des opérations avec GET retournent JSON. Pour la plupart des types de données retournées, la conversion de JSON en JavaScript peut être effectuée à l'aide de la ligne de code suivante.

var data = JSON.parse(this.response)

Toutefois, les données contenant des dates posent problème, car les dates sont transmises en tant que chaîne, par exemple 2015-10-25T17:23:55Z. Pour les convertir en objet JavaScriptDate, vous devez utiliser le paramètre reviver pour la fonction JSON.parse. Voici un exemple de fonction pouvant être utilisée pour analyser des dates.

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

Pour appliquer cette fonction, incluez-la comme paramètre, comme indiqué ici.

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

Créer une fonction réutilisable à l'aide de rappels

Lorsque vous disposez du code pour effectuer une opération spécifique, vous pouvez le réutiliser au lieu de réécrire le même code en permanence. L'étape suivante consiste à créer une bibliothèque JavaScript contenant une fonction pour effectuer l'opération avec les options disponibles. Dans ce cas, il n'existe que deux variables pour l'opération de création : le nom de l'ensemble d'entités et la définition JSON de l'entité à créer. Au lieu d'écrire la totalité du code indiqué précédemment, la même opération peut être contenue dans une fonction qui n'utilise que quelques lignes de code.

Les opérations asynchrones avec JavaScript ont traditionnellement utilisé les fonctions de rappel comme un moyen de capturer les valeurs de retour de l'opération asynchrone et de continuer la logique de votre programme. À l'aide du code de l'opération de création décrite précédemment, l'objectif ici est d'effectuer la même opération en utilisant seulement le code suivant.

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

Dans cet exemple, MyNameSpace.WebAPI représente la meilleure façon de fournir un nom unique pour les fonctions que vous utilisez.Pour plus d'informations :Définir des noms uniques pour les fonctionnalités JavaScript

Pour cette bibliothèque, nous prévoyons d'inclure des fonctions pour d'autres opérations ; il est donc possible d'utiliser des fonctions privées réutilisables pour prendre en charge les opérations. Le code suivant présente une bibliothèque qui illustre ce concept et inclut une fonction MyNameSpace.WebAPI.create avec des rappels.

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

Cette bibliothèque montre la meilleure façon de définir une fonction dans une fonction anonyme à exécution automatique (également appelée fonction anonyme à invocation automatique ou fonction anonyme à invocation immédiate) et d'associer la fonction à l'espace de noms MyNameSpace.WebAPI. Cela vous permet de définir les fonctions internes qui ne sont pas accessibles par un autre code. Toute fonction définie comme faisant partie de this est publique et les fonctions contenues dans la fonction anonyme peuvent être utilisées par les fonctions publiques, mais pas le code externe à la fonction anonyme. Le code de la fonction ne peut pas être modifié par un autre code de la page.

L'espace de noms est défini de telle façon qu'il ne remplace pas un autre code qui utilise le même espace de noms, mais il remplace les fonctions de même nom qui font partie de cet espace de noms. Vous pouvez créer des bibliothèques distinctes qui ajoutent d'autres fonctions publiques à l'espace de noms tant qu'elles ne portent pas le même nom.

La fonction MyNameSpace.WebAPI.create fournit les paramètres suivants :

Nom 

Description

entitySetName

Nom de l'ensemble d'entités pour le type d'entité que vous voulez créer.

entity

Objet avec les propriétés de l'entité que vous voulez créer.

successCallback

Fonction à appeler lorsque l'entité est créée. L'URI de l'entité créée est passé à cette fonction.

errorCallback

Fonction à appeler en cas d'erreur. L'erreur est passée à cette fonction.

Le code qui configure l'objet XMLHttpRequest a été modifié pour utiliser ces valeurs de paramètre ainsi qu'une fonction d'assistance interne supplémentaire getWebAPIPath qui recherche l'URI de l'organisation de base et ajoute l'URL de manière à ce qu'elle corresponde à l'URI racine de l'API Web ; il n'est pas nécessaire de l'inclure. L'URI de l'entité créée est transmis à successCallback s'il est défini. De même, la fonction errorHandler publique est utilisée pour analyser les erreurs retournées. La fonction errorHandler doit être publique, car elle est appelée dans le gestionnaire d'événements pour l'événement onreadystatechange, ce qui n'entre pas dans le cadre de l'espace de noms. Elle doit être appelée avec le nom complet : MyNameSpace.WebAPI.errorHandler.

Créer une fonction réutilisable à l'aide des promesses

Les rappels ont été traditionnellement utilisés pour les opérations asynchrones, mais de nombreux développeurs les trouvent peu pratiques et difficiles à lire et à déboguer, car une série d'opérations asynchrones s'appuient les unes sur les autres pour créer un code qui forme une « pyramide de malédiction », car le retrait entraîne le déplacement du code de plus en plus vers la droite de la page lorsque les fonctions anonymes sont utilisées. Bien que ce problème puisse être résolu en utilisant des fonctions nommées au lieu de fonctions anonymes, de nombreux développeurs apprécient les avantages offerts par les promesses. Un objet Promise représente une opération qui n'est pas encore terminée, mais qui devrait se terminer prochainement.

De nombreux bibliothèques et structures JavaScript tierces proposent différentes implémentations des promesses.JQuery a proposé un comportement basé sur la conception CommonJS Promises/A via l'Objet différé et d'autres insistent sur la conformité avec la spécification Promises/A+. Une explication des différences entre ces implémentations n'entre pas dans le cadre de cette rubrique. L'objectif de cette section est simplement d'expliquer comment une fonction d'assistance pour l'API Web Microsoft Dynamics 365 qui utilise un objet XMLHttpRequest natif peut être écrite pour utiliser l'Objet Promise implémenté dans la plupart des navigateurs modernes pris en charge par Microsoft Dynamics 365. Les navigateurs suivants ont une implémentation native des promesses : Google Chrome 32, Opera 19, Mozilla Firefox 29, Apple Safari 8 et Microsoft Edge.

Notes

Internet Explorer 11 n'implémente pas de promesses natives. Pour les navigateurs qui n'implémentent pas de promesses natives, vous devez inclure une bibliothèque distincte pour fournir un polyfill. Un polyfill est un code qui fournit des fonctions qui ne sont pas nativement disponibles sur un navigateur. Il existe plusieurs polyfills ou bibliothèques qui permettent à Internet Explorer 11 d'avoir des promesses : es6-promise, q.js et bluebird.

Un exemple permet de mieux démontrer l'avantage d'utiliser des promesses. Le code suivant utilise la version de rappel de MyNameSpace.WebAPI.create pour créer un compte et trois tâches qui lui sont associés.

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

Pour les besoins de cet exemple, ignorez le fait que tous ces enregistrements peuvent être créés dans une seule opération à l'aide de l'insertion profonde.Pour plus d'informations :Créer des entités associées en une opération

Le code de rappel est complexe, car il se termine au milieu du bloc de code. L'utilisation des promesses vous permet de créer les mêmes enregistrements avec le code suivant.

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

L'utilisation des promesses préserve le flux de code et permet d'intercepter toute erreur qui se produit dans une fonction d'interception unique.

La conversion de la fonction avec des rappels pour utiliser les promesses consiste à supprimer les paramètres de rappel et à retourner un objet XMLHttpRequest légèrement modifié, comme indiqué dans l'exemple de code suivant.

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

Outre la suppression des paramètres de rappel, XMLHttpRequest est inclus dans Promise et, au lieu de transmettre les résultats ou les erreurs aux rappels de réussite ou d'erreur, ceux-ci sont transmis aux paramètres resolve ou reject. Le code suivant représente la bibliothèque JavaScript complète contenant la fonction MyNameSpace.WebAPI.create. Il reste à ajouter d'autres opérations Web API réutilisables en utilisant le même modèle.

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

Voir aussi

Utilisez l'API Web Microsoft Dynamics 365
Utiliser des données Dynamics 365 à l'aide de ressources Web
Effectuer des opérations à l'aide de l'API Web
Exemples d'API Web (Javascript côté client)
Utilisez OAuth avec le partage des ressources cross-origin pour connecter une application sur une seule page à Microsoft Dynamics 365

Microsoft Dynamics 365

© 2017 Microsoft. Tous droits réservés. Copyright