Partager via


Guide pas-à-pas : Utilisation du point de terminaison SOAP d’applications modernes avec JavaScript

 

Date de publication : novembre 2016

S’applique à : Dynamics CRM 2015

Ce guide pas-à-pas montre comment créer une bibliothèque JavaScript à utiliser avec le point de terminaison SOAP et des ressources Web. Pour le moment, Mise à jour de Microsoft Dynamics CRM 2015 et de Microsoft Dynamics CRM Online 2015 ne fournit pas de bibliothèques JavaScript que vous pouvez utiliser pour appeler les messages disponibles avec le point de terminaison SOAP. Ce guide pas-à-pas explique comment créer une bibliothèque JScript pour le message Assign à l’aide de la méthode Execute du service d’organisation. Tout autre message utilisant la méthode Execute suivra un modèle similaire. La création d’une bibliothèque JavaScript pour n’importe quel message nécessite un processus similaire. Pour consulter un exemple de bibliothèque JavaScript développée avec ce processus, voir Exemple : récupérer les métadonnées de l’entité à l’aide de JavaScript.

Notes

Pour une bibliothèque complète d'exemples JavaScript utilisant le point de terminaison SOAP, voir la bibliothèque de Sdk.Soap.js. La bibliothèque Sdk.Soap.js a été créée grâce au processus décrit ici.

Le processus consiste à capturer les requêtes HTTP et les réponses envoyées par une application de console de code géré, puis à créer une bibliothèque JavaScript disposant de fonctions pour envoyer les mêmes requêtes et traiter des réponses similaires. Il est courant d’utiliser une application comme Fiddler pour capturer les requêtes et les réponses HTTP, mais Fiddler et les applications similaires ne peuvent pas capturer le trafic HTTP chiffré utilisé pour l’instance locale de Microsoft Dynamics CRM 2015. L’exemple de solution SOAPLogger fourni capture les requêtes HTTP avant qu’elles ne soient chiffrées et les réponses HTTP une fois déchiffrées. L'exemple de solution SOAPLogger fonctionne pour Mise à jour de Microsoft Dynamics CRM 2015 et de Microsoft Dynamics CRM Online 2015.SOAPLogger filtre également le trafic HTTP qui n'est pas approprié pour la tâche de création d'une bibliothèque JScript.

Ce guide pas-à-pas vous aide à effectuer les tâches suivantes :

  1. Dans Capturer l’exemple de requête et de réponse HTTP, vous allez modifier la méthode Run de l’exemple SOAPLogger pour effectuer une demande Assign avec du code géré.

  2. Vous exécuterez ensuite la solution SOAPLogger pour générer des informations sur les requêtes HTTP envoyées et les réponses reçues.

  3. Dans Créer une bibliothèque JScript, vous allez créer une bibliothèque JScript basée sur le trafic HTTP capturé pour envoyer et recevoir le message Assign à l’aide de la méthode Execute du service d’organisation.

  4. Dans Tester la bibliothèque JScript, vous allez tester la bibliothèque JScript pour vérifier qu’elle peut être utilisée pour attribuer des enregistrements.

  5. Dans Créer une ressource Web interactive, vous allez créer une ressource Web HTML qui utilise la bibliothèque pour attribuer des enregistrements Account à un utilisateur sélectionné, comme illustré dans la capture d’écran suivante.

    Page Attribuer des comptes

Une solution gérée représentant ce guide pas-à-pas terminé est disponible dans le package SDK dans SDK\SampleCode\JS\SOAPForJScript\SOAPEndpointforJScript_1_0_0_1_managed.zip. Téléchargez le package Kit de développement logiciel (SDK) de Microsoft Dynamics CRM. Vous pouvez installer (importer) cette solution et afficher les résultats terminés. Comme il s’agit d’une solution gérée, vous pouvez facilement la désinstaller (supprimer) pour la supprimer complètement de votre système.

SDK\SampleCode\JS\SOAPForJScript\SOAPForJScript.sln est une solution Visual Studio qui contient les fichiers HTML et JS avec le code de ce guide pas-à-pas.

Conditions préalables

  • Vous devez être capable d’écrire du code géré correspondant aux fonctionnalités que vous souhaitez exécuter avec JScript.

  • Vous devez avoir accès à l’exemple SOAPLogger disponible avec les fichiers de téléchargement du SDK sur SDK\SampleCode\CS\Client\SOAPLogger.

    Notes

    L’exemple SOAPLogger dans le SDK Microsoft Dynamics CRM est uniquement disponible pour Microsoft Visual C#. Si vous préférez une version Microsoft Visual Basic .NET, consultez Microsoft Dynamics CRM VB.Net SoapLogger sur CodePlex.

  • Vous avez besoin de Microsoft Visual Studio pour exécuter la solution SOAPLogger.

  • Vous devez posséder de bonnes connaissances de JScript et de la programmation asynchrone avec XMLHttpRequest.

Capturer l’exemple de requête et de réponse HTTP

Modifiez la solution SOAPLogger pour ajouter du code pour exécuter une instance de AssignRequest à l’aide de SoapLoggerOrganizationService.SoapLoggerOrganizationService hérite de IOrganizationService et ajoute la capacité de générer un fichier journal qui affiche le trafic HTTP approprié envoyé et reçu.

  1. Dans Microsoft Visual Studio, ouvrez la solution SOAPLogger à l’adresse SDK\SampleCode\CS\Client\SOAPLogger\SOAPLogger.sln.

  2. Dans le fichier SoapLogger.cs, recherchez la méthode Run, comme illustré dans l’exemple suivant :

    
    public void Run(ServerConnection.Configuration serverConfig)
    {
     try
     {
    
      // Connect to the Organization service. 
      // The using statement assures that the service proxy will be properly disposed.
         using (_serviceProxy = new OrganizationServiceProxy(serverConfig.OrganizationUri, serverConfig.HomeRealmUri, serverConfig.Credentials, serverConfig.DeviceCredentials))
      {
       // This statement is required to enable early-bound type support.
       _serviceProxy.EnableProxyTypes();
    
       IOrganizationService service = (IOrganizationService)_serviceProxy;
    
    
       using (StreamWriter output = new StreamWriter("output.txt"))
       {
    
        SoapLoggerOrganizationService slos = new SoapLoggerOrganizationService(serverConfig.OrganizationUri, service, output);
    
        //Add the code you want to test here:
        // You must use the SoapLoggerOrganizationService 'slos' proxy rather than the IOrganizationService proxy you would normally use.
    
    
    
       }
    
    
      }
    
     }
    
     // Catch any service fault exceptions that Microsoft Dynamics CRM throws.
     catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault>)
     {
      // You can handle an exception here or pass it back to the calling method.
      throw;
     }
    }
    
  3. Identifiez un ID valide pour un enregistrement SystemUser et l’ID d’un enregistrement Account non attribué à cet utilisateur.

    Conseil

    Pour obtenir l’Id d’un enregistrement dans l’application, ouvrez celui-ci et utilisez la commande Copier un lien. Collez le lien dans le Bloc-notes et isolez la partie qui contient la valeur de paramètre id sans les parenthèses encodées (« %7b » = « { ») et (« %7d » = « } »). Par exemple, le code suivant représente une URL pour un enregistrement Account.<your organization root url>/main.aspx?etc=1&id=%7bF2CA52DE-552D-E011-A8FB-00155DB059BE%7d&pagetype=entityrecord>. La valeur d’ID est F2CA52DE-552D-E011-A8FB-00155DB059BE.

    Utilisez ces valeurs pour remplacer les valeurs de l’espace réservé dans le code ci-dessous et ajouter le code à la méthode Run comme indiqué. Pour plus d’informations sur la demande Assign, voir AssignRequest.

    Guid userId = new Guid("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
    Guid accountId = new Guid("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
    AssignRequest assign = new AssignRequest{Assignee = new EntityReference(SystemUser.EntityLogicalName, userId),Target = new EntityReference(Account.EntityLogicalName, accountId)};
    AssignResponse assignResp = (AssignResponse)slos.Execute(assign);
    
  4. Appuyez sur F5 pour déboguer l’application. Entrez les informations relatives au serveur et vos informations d’authentification. Si le code s’exécute correctement l’enregistrement de compte sera désormais attribué à l’utilisateur spécifié. Pour plus d’informations sur l’exécution de l’exemple de code, voir Exécuter un programme simple à l’aide des services Web Microsoft Dynamics CRM 2015

  5. Dans les dossiers de projet SOAPLogger, accédez aux dossiers bin et Debug et recherchez le fichier output.txt.

  6. Ouvrez le fichier output.txt et vérifiez le contenu. Il doit ressembler au code suivant, sauf que les valeurs GUID réelles remplaceront l’espace réservé "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX”.

    HTTP REQUEST
    --------------------------------------------------
    POST <your server root>/XRMServices/2011/Organization.svc/web
    Content-Type: text/xml; charset=utf-8
    SOAPAction: https://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute
    
    <s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
     <s:Body>
      <Execute xmlns="https://schemas.microsoft.com/xrm/2011/Contracts/Services"
               xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
       <request i:type="b:AssignRequest"
                xmlns:a="https://schemas.microsoft.com/xrm/2011/Contracts"
                xmlns:b="https://schemas.microsoft.com/crm/2011/Contracts">
        <a:Parameters xmlns:c="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
         <a:KeyValuePairOfstringanyType>
          <c:key>Target</c:key>
          <c:value i:type="a:EntityReference">
           <a:Id>XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX</a:Id>
           <a:LogicalName>account</a:LogicalName>
           <a:Name i:nil="true" />
          </c:value>
         </a:KeyValuePairOfstringanyType>
         <a:KeyValuePairOfstringanyType>
          <c:key>Assignee</c:key>
          <c:value i:type="a:EntityReference">
           <a:Id>XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX</a:Id>
           <a:LogicalName>systemuser</a:LogicalName>
           <a:Name i:nil="true" />
          </c:value>
         </a:KeyValuePairOfstringanyType>
        </a:Parameters>
        <a:RequestId i:nil="true" />
        <a:RequestName>Assign</a:RequestName>
       </request>
      </Execute>
     </s:Body>
    </s:Envelope>
    --------------------------------------------------
    
    HTTP RESPONSE
    --------------------------------------------------
    <s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
     <s:Body>
      <ExecuteResponse xmlns="https://schemas.microsoft.com/xrm/2011/Contracts/Services"
                       xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
       <ExecuteResult i:type="b:AssignResponse"
                      xmlns:a="https://schemas.microsoft.com/xrm/2011/Contracts"
                      xmlns:b="https://schemas.microsoft.com/crm/2011/Contracts">
        <a:ResponseName>Assign</a:ResponseName>
        <a:Results xmlns:c="http://schemas.datacontract.org/2004/07/System.Collections.Generic" />
       </ExecuteResult>
      </ExecuteResponse>
     </s:Body>
    </s:Envelope>
    --------------------------------------------------
    
  7. Notez l’emplacement des variables que vous avez passées avec votre code, notamment le nom logique de l’entité Account.

Vous avez correctement capturé les zones appropriées du trafic HTTP qui a lancé l’opération assign.

Créer une bibliothèque JScript

La façon exacte dont vous souhaitez créer votre bibliothèque vous incombe. Chaque code JScript doit avoir les éléments suivants :

  • Une stratégie pour garantir l’unicité du nom de chaque fonction.

  • Un moyen de récupérer l’URL du point de terminaison SOAP pour les ressources Web.

  • Des méthodes distinctes pour envoyer la demande et recevoir la réponse de façon asynchrone.

  • Une fonctionnalité pour traiter tous les défauts WCF retournés.

La bibliothèque JScript suivante contient ces éléments et inclut les fonctions assignRequest et assignResponse pour utiliser le message Assign basé sur les requêtes et les réponses HTTP capturées avec SOAPLogger.


if (typeof (SDK) == "undefined")
{ SDK = { __namespace: true }; }
//This will establish a more unique namespace for functions in this library. This will reduce the 
// potential for functions to be overwritten due to a duplicate name when the library is loaded.
SDK.SOAPSamples = {
 _getClientUrl: function () {
  ///<summary>
  /// Returns the URL for the SOAP endpoint using the context information available in the form
  /// or HTML Web resource.
  ///</summary
  var OrgServicePath = "/XRMServices/2011/Organization.svc/web";
  var clientUrl = "";
  if (typeof GetGlobalContext == "function") {
   var context = GetGlobalContext();
   clientUrl = context.getClientUrl();
  }
  else {
   if (typeof Xrm.Page.context == "object") {
    clientUrl = Xrm.Page.context.getClientUrl();
   }
   else
   { throw new Error("Unable to access the server URL"); }
  }

  return clientUrl + OrgServicePath;
 },
 assignRequest: function (Assignee, Target, Type, successCallback, errorCallback) {
  ///<summary>
  /// Sends the Assign Request
  ///</summary>
  this._parameterCheck(Assignee, "GUID", "The SDK.SOAPSamples.assignRequest method Assignee parameter must be a string Representing a GUID value.");
  ///<param name="Assignee" Type="String">
  /// The GUID representing the  System user that the record will be assigned to.
  ///</param>
  this._parameterCheck(Target, "GUID", "The SDK.SOAPSamples.assignRequest method Target parameter must be a string Representing a GUID value.");
  ///<param name="Target" Type="String">
  /// The GUID representing the user-owned entity record that will be assigne to the Assignee.
  ///</param>
  this._parameterCheck(Type, "String", "The SDK.SOAPSamples.assignRequest method Type parameter must be a string value.");
  Type = Type.toLowerCase();
  ///<param name="Type" Type="String">
  /// The Logical name of the user-owned entity. For example, 'account'.
  ///</param>
  if (successCallback != null)
  this._parameterCheck(successCallback, "Function", "The SDK.SOAPSamples.assignRequest method successCallback parameter must be a function.");
  ///<param name="successCallback" Type="Function">
  /// The function to perform when an successfult response is returned.
  ///</param>
  this._parameterCheck(errorCallback, "Function", "The SDK.SOAPSamples.assignRequest method errorCallback parameter must be a function.");
  ///<param name="errorCallback" Type="Function">
  /// The function to perform when an error is returned.
  ///</param>
  //The request is simply the soap envelope captured by the SOAPLogger with variables added for the 
  // values passed. All quotations must be escaped to create valid JScript strings.
  var request = [];

     request.push("<s:Envelope xmlns:s=\"https://schemas.xmlsoap.org/soap/envelope/\">");
     request.push("<s:Body>");
     request.push("<Execute xmlns=\"https://schemas.microsoft.com/xrm/2011/Contracts/Services\"");
     request.push(" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">");
     request.push("<request i:type=\"b:AssignRequest\"");
     request.push(" xmlns:a=\"https://schemas.microsoft.com/xrm/2011/Contracts\"");
     request.push(" xmlns:b=\"https://schemas.microsoft.com/crm/2011/Contracts\">");
     request.push("<a:Parameters xmlns:c=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">");
     request.push("<a:KeyValuePairOfstringanyType>");
     request.push("<c:key>Target</c:key>");
     request.push("<c:value i:type=\"a:EntityReference\">");
     request.push("<a:Id>" + this._xmlEncode(Target) + "</a:Id>");
     request.push("<a:LogicalName>" + this._xmlEncode(Type) + "</a:LogicalName>");
     request.push("<a:Name i:nil=\"true\" />");
     request.push("</c:value>");
     request.push("</a:KeyValuePairOfstringanyType>");
     request.push("<a:KeyValuePairOfstringanyType>");
     request.push("<c:key>Assignee</c:key>");
     request.push("<c:value i:type=\"a:EntityReference\">");
     request.push("<a:Id>" + this._xmlEncode(Assignee) + "</a:Id>");
     request.push("<a:LogicalName>systemuser</a:LogicalName>");
     request.push("<a:Name i:nil=\"true\" />");
     request.push("</c:value>");
     request.push("</a:KeyValuePairOfstringanyType>");
     request.push("</a:Parameters>");
     request.push("<a:RequestId i:nil=\"true\" />");
     request.push("<a:RequestName>Assign</a:RequestName>");
     request.push("</request>");
     request.push("</Execute>");
     request.push("</s:Body>");
     request.push("</s:Envelope>");

  var req = new XMLHttpRequest();
  req.open("POST", SDK.SOAPSamples._getClientUrl(), true)
  // Responses will return XML. It isn't possible to return JSON.
  req.setRequestHeader("Accept", "application/xml, text/xml, */*");
  req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
  req.setRequestHeader("SOAPAction", "https://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
  req.onreadystatechange = function () { SDK.SOAPSamples.assignResponse(req, successCallback, errorCallback); };
  req.send(request.join(""));

 },
 assignResponse: function (req, successCallback, errorCallback) {
  ///<summary>
  /// Recieves the assign response
  ///</summary>
  ///<param name="req" Type="XMLHttpRequest">
  /// The XMLHttpRequest response
  ///</param>
  ///<param name="successCallback" Type="Function">
  /// The function to perform when an successfult response is returned.
  /// For this message no data is returned so a success callback is not really necessary.
  ///</param>
  ///<param name="errorCallback" Type="Function">
  /// The function to perform when an error is returned.
  /// This function accepts a JScript error returned by the _getError function
  ///</param>
     if (req.readyState == 4) {
         req.onreadystatechange = null; //avoids memory leaks
   if (req.status == 200) {
    if (successCallback != null)
    { successCallback(); }
   }
   else {
    errorCallback(SDK.SOAPSamples._getError(req.responseXML));
   }
  }
 },
 _getError: function (faultXml) {
  ///<summary>
  /// Parses the WCF fault returned in the event of an error.
  ///</summary>
  ///<param name="faultXml" Type="XML">
  /// The responseXML property of the XMLHttpRequest response.
  ///</param>
  var errorMessage = "Unknown Error (Unable to parse the fault)";
  if (typeof faultXml == "object") {
   try {
    var bodyNode = faultXml.firstChild.firstChild;
    //Retrieve the fault node
    for (var i = 0; i < bodyNode.childNodes.length; i++) {
     var node = bodyNode.childNodes[i];

     //NOTE: This comparison does not handle the case where the XML namespace changes
     if ("s:Fault" == node.nodeName) {
      for (var j = 0; j < node.childNodes.length; j++) {
       var faultStringNode = node.childNodes[j];
       if ("faultstring" == faultStringNode.nodeName) {
        errorMessage = faultStringNode.textContent;
        break;
       }
      }
      break;
     }
    }
   }
   catch (e) { };
  }
  return new Error(errorMessage);
 },
 _xmlEncode: function (strInput) {
  var c;
  var XmlEncode = '';

  if (strInput == null) {
   return null;
  }
  if (strInput == '') {
   return '';
  }

  for (var cnt = 0; cnt < strInput.length; cnt++) {
   c = strInput.charCodeAt(cnt);

   if (((c > 96) &amp;&amp; (c < 123)) ||
            ((c > 64) &amp;&amp; (c < 91)) ||
            (c == 32) ||
            ((c > 47) &amp;&amp; (c < 58)) ||
            (c == 46) ||
            (c == 44) ||
            (c == 45) ||
            (c == 95)) {
    XmlEncode = XmlEncode + String.fromCharCode(c);
   }
   else {
    XmlEncode = XmlEncode + '&amp;#' + c + ';';
   }
  }

  return XmlEncode;
 },
 _parameterCheck: function (parameter, type, errorMessage) {
  switch (type) {
   case "String":
    if (typeof parameter != "string") {
     throw new Error(errorMessage);
    }
    break;
   case "Function":
    if (typeof parameter != "function") {
     throw new Error(errorMessage);
    }
    break;
   case "EntityFilters":
    var found = false;
    for (x in this.EntityFilters) {
     if (this.EntityFilters[x] == parameter) {
      found = true;
      break;
     }
    }
    if (!found) {
     throw new Error(errorMessage);
    }
    break;
   case "Boolean":
    if (typeof parameter != "boolean") {
     throw new Error(errorMessage);
    }
    break;
   case "GUID":
    var re = new RegExp("[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}");
    if (!(typeof parameter == "string" &amp;&amp; re.test(parameter))) {
     throw new Error(errorMessage);
    }

    break;
   default:
    throw new Error("An invalid type parameter value was passed to the SDK.MetaData._parameterCheck function.");
    break;
  }
 },
 __namespace: true
};

Tester la bibliothèque JScript

Après avoir préparé votre bibliothèque JScript, réalisez quelques tests initiaux pour vérifier qu’elle fonctionne comme prévu. Étant donné que l’authentification n’a lieu que dans l’application, vous devez créer une ressource Web de script dans Microsoft Dynamics CRM 2015 à l’aide du contenu de votre bibliothèque. Pour utiliser les fonctions dans votre bibliothèque, vous devez disposer d’un certain nombre d’éléments d’interface utilisateur, un formulaire ou une ressource Web HTML pour appeler les fonctions JScript dans votre bibliothèque. La procédure suivante décrit l’utilisation d’une ressource Web HTML simple pour tester les fonctions dans la bibliothèque.

  1. Créez un document HTML à l’aide du code suivant :

    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
     <title>Assign Test</title>
     <meta http-equiv="X-UA-Compatible" content="IE=edge" />
      <script src="../ClientGlobalContext.js.aspx" type="text/javascript"></script>
     <script src="Scripts/SDK.REST.js" type="text/javascript"></script>
     <script src="Scripts/SDK.SOAPSample.Assign.js" type="text/javascript"></script>
     <script type="text/javascript">
      var resultsArea = null;
      var userid;
      var accountid;
      var userLookup;
      var accountLookup;
      var accountsToShow = 10;
      var usersToShow = 10;
      var users = [];
      var accounts = [];
    
      document.onreadystatechange = function () {
       ///<summary>
       /// Initializes the sample when the document is ready
       ///</summary>
       if (document.readyState == "complete") {
        userid = document.getElementById("userid");
        accountid = document.getElementById("accountid");
        resultsArea = document.getElementById("results");
        userLookup = document.getElementById("userLookup");
        accountLookup = document.getElementById("accountLookup");
    
        populateUserLookup();
        populateAccountLookup();
    
       }
      }
    
      function testAssign() {
       //The field to enter the user id of the person the account record should be assigned to.
       userid.value;
       // The field to enter the account id of the account record to assign to the user
       accountid.value;
       // Since the response does not include any data to parse, simply display a success message.
       var successCallback = function () { setText(resultsArea, "Success!"); };
       // Display the error from the message passed back from the response.
       var errorCallback = function (error) { setText(resultsArea,"errorCallback error: "+error.message); };
       // Call the function
       try {
        SDK.SOAPSamples.assignRequest(userid.value, accountid.value, "account", successCallback, errorCallback);
       }
       catch (e) {
        setText(resultsArea, e.message);
       }
    
      }
    
      function populateUserLookup() {
       SDK.REST.retrieveMultipleRecords("SystemUser",
       "$top=" + usersToShow + "&amp;$select=FullName,SystemUserId&amp;$filter=FullName ne 'INTEGRATION' and FullName ne 'SYSTEM'",
       function (results) {
        for (var i = 0; i < results.length; i++) {
         users.push(results[i]);
        }
       },
       function (error) {
        alert(error.message);
       },
       function () {
        for (var i = 0; i < users.length; i++) {
         var user = users[i];
         userLookup.options[i] = new Option(user.FullName, user.SystemUserId);
        }
        userid.value = userLookup.options[0].value;
    
        userLookup.onchange = function () {
         userid.value = userLookup.options[userLookup.selectedIndex].value;
         clearMessage();
        };
    
       });
      }
    
      function populateAccountLookup() {
       SDK.REST.retrieveMultipleRecords("Account",
        "$top=" + accountsToShow + "&amp;$select=AccountId,Name,OwnerId",
       function (results) {
        for (var i = 0; i < results.length; i++) {
         accounts.push(results[i]);
    
        }
       },
       function (error) {
        alert(error.message);
       },
       function () {
        for (var i = 0; i < accounts.length; i++) {
         var account = accounts[i];
         accountLookup.options[i] = new Option(account.Name + " : " + account.OwnerId.Name, account.AccountId);
    
        }
        accountid.value = accountLookup.options[0].value;
    
        accountLookup.onchange = function () {
         accountid.value = accountLookup.options[accountLookup.selectedIndex].value;
         clearMessage();
        };
       });
      }
    
      function clearMessage() {
       setText(resultsArea, "");
      }
    
      function setText(element, text) {
       if (typeof (element.innerText) != "undefined") {
        element.innerText = text;
       }
       else {
        element.textContent = text;
       }
    
      }
    
     </script>
    </head>
    <body>
     <table>
      <tr>
       <td>
        <label for="userid">
         SystemUserId:</label>
       </td>
       <td>
        <input id="userid" type="text" style="width:270px;"  />
       </td>
       <td>
       <select id="userLookup"></select>
       </td>
      </tr>
      <tr>
       <td>
        <label for="accountid">
         AccountId:</label>
       </td>
       <td>
        <input id="accountid" type="text" style="width:270px;" />
       </td>
          <td>
       <select id="accountLookup"></select>
       </td>
      </tr>
     </table>
    
    
     <button id="testAssign" title="Click this button to test the testAssign function." onclick="testAssign();">
      Test Assign</button>
     <div id="results">
      &amp;nbsp;</div>
    </body>
    </html>
    
  2. Créez une ressource Web HTML à l’aide de ce code. Le nom complet de la ressource Web HTML dépend du préfixe de personnalisation de votre solution. En supposant que votre préfixe de personnalisation de solution est « new », nommez cette ressource Web HTML « new_/AssignTest.htm ». Le préfixe de personnalisation spécifique utilisé n’a aucun impact sur cet exemple tant que toutes les ressources Web utilisent le même préfixe de personnalisation.

  3. Créez une ressource Web de script avec le contenu de la bibliothèque JScript. Nommez cette ressource Web « new_/Scripts/SDK.SOAPSample.Assign.js ».

  4. Publiez toutes les personnalisations et ouvrez la ressource Web new_/AssignTest.htm. Cliquez sur le bouton Aperçu.

  5. En utilisant le processus de l’étape trois de la procédure No text is specified for bookmark or legacy link 'c9a435ab-a4cb-4e0c-9ef7-b7ba66278407#BKMK_EditSoapLogger'., identifiez les valeurs d’utilisateur système et d’ID d’enregistrement de compte valides et collez-les dans la page. Ensuite, cliquez sur Test Assign pour vérifier que vous obtenez une réponse correcte.

  6. Entrez des valeurs non valides pour vérifier que l’erreur est analysée correctement.

    Par exemple, si vous entrez « Un magasin (exemple) » à la place de l’ID pour un compte, vous devez vous attendre au message d’erreur suivant :

    The formatter threw an exception while trying to deserialize the message: 
    There was an error while trying to deserialize parameter https://schemas.microsoft.com/xrm/2011/Contracts/Services:request. 
    The InnerException message was 'There was an error deserializing the object of type Microsoft.Xrm.Sdk.OrganizationRequest. 
    The value 'A Store (sample)' cannot be parsed as the type 'Guid'.'.  Please see InnerException for more details.
    

    S’il n’y a aucun compte d’enregistrement pour AccountId, le message que vous recevez est :

    Account With Id = 883c3084-1f2f-e011-ad66-00155dba3814 Does Not Exist
    

Créer une ressource Web interactive

L’étape suivante consiste à utiliser votre bibliothèque JScript dans un script de formulaire, une commande de ruban ou une ressource Web. L’exemple de code suivant représente une ressource Web HTML qui utilise le point de terminaison REST pour récupérer les listes des enregistrements SystemUser et Account afin de fournir une interface utilisateur interactive pour attribuer les enregistrements de comptes aux utilisateurs. Cette page utilise la ressource Web de script Scripts/SDK.SOAPSample.Assign.js et une ressource Web de script à l’aide de la bibliothèque json2.js pour prendre en charge l’utilisation des objets JSON avec le point de terminaison REST. La bibliothèque SDK.REST.js permet de récupérer les données à l’aide du point de terminaison REST.


<html lang="en-us">
<head>
 <title>Assign Accounts Page</title>
 <meta http-equiv="X-UA-Compatible" content="IE=edge" />
 <style type="text/css">
  body
  {
   font-family: Segoe UI;
   background-color: #EFF2F6;
  }
  .dataTable
  {
   border-collapse: collapse;
   border: 1px solid black;
  }
  .tableHead
  {
   background-color: #C0C0C0;
   width: 100%;
  }
  .grid
  {
   border-bottom: 1px solid black;
  }
  td
  {
   padding-left: 5px;
   padding-right: 5px;
  }
  #accountList
  {
   background-color: White;
  }
  #checkboxCol
  {
   border-right: 1px solid black;
   width: 20px;
  }
  #nameCol
  {
   border-right: 1px solid black;
   width: 300px;
  }
  #ownerCol
  {
   width: 300px;
  }
 </style>
 <script src="../ClientGlobalContext.js.aspx" type="text/javascript"></script>
 <script src="Scripts/SDK.REST.js" type="text/javascript"></script>
 <script src="Scripts/SDK.SOAPSample.Assign.js" type="text/javascript"></script>
 <script type="text/javascript">
  //Set variables for page elements
  var userSelect; //The select control used to select the user to assign records to.
  var accountList; //The tbody element that rows will be added to for each retrieved account
  var selectAll; //The checkbox to select all the retrieved accounts
  var btnAssign; //The button to assign assign the accounts
  var tableCaption; //A label hidden on load
  var dataTable; //the table element hidden on load
  var alertFlag; // Alert flag to indicate the changes
  var users = []; //SystemUser records retrieved
  var accounts = []; //Accounts not assigned to the currently selected user.
  var accountsToShow = 5;
  var suppressRetrievedAccountsAlert = false;
  var accountsToAssign = [];
  var userId = null;

  function startSample() {
   ///<summary>
   /// Starts the sample
   ///</summary>
   alertFlag = document.getElementById("dispalert");
   userSelect = document.getElementById("userList");
   //A new set of a 5 accounts will be retrieved when the user changes
   userSelect.onchange = getAccounts;

   accountList = document.getElementById("accountList");
   selectAll = document.getElementById("selectAll");
   //When the select all checkbox is clicked, toggle the selection for each row of the table.
   selectAll.onclick = toggleSelectAllRecords;
   btnAssign = document.getElementById("btnAssign");
   //Add a helper function to enable or disable the assign button.
   btnAssign.setEnabled = setEnabled;
   //Set the event handler to the Assign button
   btnAssign.onclick = assignAccounts;
   tableCaption = document.getElementById("tableCaption");
   dataTable = document.getElementById("dataTable");
   var divSample = document.getElementById("divSample");
   //Load the list of users
   getUsers();
   divSample.style.display = "block";

   document.getElementById("btnStart").setAttribute("disabled", "disabled");

  }
  function getUsers() {
   SDK.REST.retrieveMultipleRecords("SystemUser",
   "$select=FullName,SystemUserId&amp;$filter=FullName ne 'INTEGRATION' and FullName ne 'SYSTEM'",
   function (results) {
    for (var i = 0; i < results.length; i++) {
     users.push(results[i]);
    }
   },
   function (error) {
    showMessage(error.message);
   },
   function () {
    if (users.length > 1) {
     for (var i = 0; i < users.length; i++) {
      var user = users[i];
      userSelect.options[i + 1] = new Option(user.FullName, user.SystemUserId);
     }
     userSelect.removeAttribute("disabled");

     if (alertFlag.checked == true) {
      alert(users.length + " system users retrieved");
     }

    }
    else {
     var notification = "This sample requires that more than one user is available in the organization.";
     showMessage(notification);
     if (alertFlag.checked == true) {
      alert("This sample requires that more than one user is available in the organization.");
     }

    }
   });
  }
  function getAccounts() {
   //Clear out any records displayed in the table
   clearAccountList();
   var selectedUserId = userSelect.options[userSelect.selectedIndex].value;
   if (selectedUserId != "none") {

    SDK.REST.retrieveMultipleRecords("Account",
    "$top=" + accountsToShow + "&amp;$select=AccountId,Name,OwnerId&amp;$filter=OwnerId/Id ne (guid'" + encodeURIComponent(selectedUserId) + "')",
    function (results) {
     accounts.length = 0;
     for (var i = 0; i < results.length; i++) {
      accounts.push(results[i]);
     }
    },
    function (error) {
     showMessage(error.message);
    },
    function () {
     //onComplete
     if (accounts.length > 0) {

      for (var i = 0; i < accounts.length; i++) {
       var account = accounts[i];

       var row = document.createElement("tr");
       row.setAttribute("class", "grid");
       row.setAttribute("id", account.AccountId);
       var checkboxCell = document.createElement("td");
       var checkbox = document.createElement("input");
       checkbox.setAttribute("type", "checkbox");
       checkbox.onclick = validateAssignButton;
       checkboxCell.appendChild(checkbox);
       row.appendChild(checkboxCell);
       var nameCell = document.createElement("td");
       setText(nameCell, account.Name);
       row.appendChild(nameCell);
       var userNameCell = document.createElement("td");
       setText(userNameCell, account.OwnerId.Name);
       row.appendChild(userNameCell);
       accountList.appendChild(row);



      }

      if (alertFlag.checked == true &amp;&amp; !suppressRetrievedAccountsAlert) {
       alert(accounts.length + " account records retrieved.");
       suppressRetrievedAccountsAlert = false;

      }
     }
     else {
      //If no records are returned display a message.
      clearAccountList();
      var row = document.createElement("tr");
      var cell = document.createElement("td");
      cell.setAttribute("colSpan", "3");
      setText(cell, "No Accounts were retrieved");
      row.appendChild(cell);
      accountList.appendChild(row);

     }
     //Show any of the UI elements that are initially hidden
     setVisibleUIElements(true);
    });
   }
   else { setVisibleUIElements(false); }
  }
  function assignAccounts() {
   ///<summary>
   /// queues the selected accounts to be assigned sequentially
   ///</summary>
   userId = userSelect.options[userSelect.selectedIndex].value;

   var checkboxes = accountList.getElementsByTagName("input");
   for (var i = checkboxes.length - 1; i >= 0; i--) {
    if (checkboxes[i].checked) {
     var accountId = checkboxes[i].parentElement.parentElement.id;
     accountsToAssign.push(accountId);
    }
   }
   assignNextAccount();
   selectAll.checked = false;
  }
  function assignNextAccount() {
   /// <summary>Assigns the queued accounts</summary>
   //Prevents a generic SQL error that can occur when too many assign requests occur in rapid succession
   if (accountsToAssign.length > 0) {
    SDK.SOAPSamples.assignRequest(userId, accountsToAssign.shift(), "account", function () {
     assignNextAccount();
    }, function (error) {
     showMessage("There was an error assigning the account with Id :" + accountId + ". The error message is " + error.message + ".");
     assignNextAccount();
    });

   }
   else {
    suppressRetrievedAccountsAlert = true;
    getAccounts();
    btnAssign.setEnabled(false)
    if (alertFlag.checked == true) {
     alert("Record assignment completed and next set of records retrieved.");
    }
   }


  }
  function showMessage(message) {
   ///<summary>
   /// Helper function to display message on the page if necessary.
   ///</summary
   var dvMessage = document.createElement("div");
   dvMessage.innerHTML = SDK.SOAPSamples._xmlEncode(message);
   document.getElementById("status").appendChild(dvMessage);
  }
  function clearAccountList() {
   ///<summary>
   /// Helper function remove rows from the Account List table.
   ///</summary
   for (var i = (accountList.rows.length - 1) ; i >= 0; i--) {
    accountList.deleteRow(i);
   }
   accounts.length = 0;

  }
  function toggleSelectAllRecords() {
   ///<summary>
   /// Helper function to toggle all selected rows in the account list table.
   ///</summary
   var checkboxes = accountList.getElementsByTagName("input");
   for (var i = 0; i < checkboxes.length; i++) {
    checkboxes[i].checked = this.checked;
   }
   btnAssign.setEnabled(this.checked);

  }
  function validateAssignButton() {
   ///<summary>
   /// Helper function to enable the Assign Records button when rows are selected.
   ///</summary
   if (this.checked == true)
   { btnAssign.setEnabled(true); }
   else {
    selectAll.checked = false;
    var checkboxes = accountList.getElementsByTagName("input");
    var checked = false;
    for (var i = 0; i < checkboxes.length; i++) {
     if (checkboxes[i].checked == true) {
      checked = true;
      break;
     }
    }
    btnAssign.setEnabled(checked);
   }
  }
  function setEnabled(bool) {
   ///<summary>
   /// Helper method attached to the Assign button to make it easier to enable/disable the button.
   ///</summary
   if (bool)
   { this.removeAttribute("disabled"); }
   else
   { this.setAttribute("disabled", "disabled"); }
  }
  function setVisibleUIElements(display) {
   ///<summary>
   /// Helper function to show those UI elements initially hidden.
   ///</summary
   if (display) {
    show(tableCaption);
    show(dataTable);
    show(btnAssign);
   }
   else {
    hide(tableCaption);
    hide(dataTable);
    hide(btnAssign);
   }

  }
  function show(element) {
   if (element.tagName.toLowerCase() == "table") {
    element.style.display = "table";
   }
   else {
    element.style.display = "block";
   }

  }
  function hide(element) {
   element.style.display = "none";
  }
  // setText  mitigate differences in how browsers set or get text content.
  function setText(node, text) {
   if (typeof (node.innerText) != "undefined") {
    node.innerText = text;
   }
   else {
    node.textContent = text;
   }

  }

 </script>
</head>
<body>
 <h1>
  Assign Accounts Sample
 </h1>
 <p>
  This page requires JavaScript and will update dynamically.
 </p>
 <p>
  <input id="dispalert" name="dispalert" type="checkbox" value="alert" /><label for="dispalert">Display alert window when data changes.</label>
 </p>
 <p>
  Click the <b>Start</b> button to begin the sample.
 </p>
 <input type="button" id="btnStart" name="btnStart" value="Start" onclick="startSample()" />
 <div id="divSample" style="display: none">
  <label for="userList">
   User:
  </label>
  <select id="userList" name="userList" title="Select a system user from this list." disabled>
   <option value="none">Select a User...</option>
  </select>
  <p id="tableCaption" style="display: none;">
   Top 5 Accounts not assigned to the selected user:
  </p>
  <table class="dataTable" id="dataTable" style="display: none; width: 100%;">
   <thead>
    <tr class="tableHead">
     <th scope="col" id="checkboxCol">
      <input id="selectAll" name="selectAll" title="Select this to select all records" type="checkbox" /><label for="selectAll">Select&amp;nbsp;All</label>
     </th>
     <th scope="col" id="nameCol">
      Name
     </th>
     <th scope="col" id="ownerCol">
      Owner
     </th>
    </tr>
   </thead>
   <tbody id="accountList"></tbody>
  </table>


  <label style="display: none;" for="btnAssign">
   Click to assign selected records
  </label>
  <button id="btnAssign" name="btnAssign" disabled style="display: none; float: right;">
   Assign Records
  </button>
  <label style="display: none;" for="btnAssign">
   Click to assign selected records
  </label>
  <button id="Button1" name="btnAssign" disabled style="display: none; float: right;">
   Assign Records
  </button>
 </div>
 <div id="status">
  &amp;nbsp;
 </div>
</body>
</html>

Voir aussi

AssignRequest
Exemple : récupérer les métadonnées de l’entité à l’aide de JavaScript
Utilisez le point de terminaison SOAP d’application moderne pour les applications modernes avec des ressources Web
Utiliser des données du service Web dans les ressources Web (point de terminaison OData et SOAP d’applications modernes)
Écrire des applications et des extensions de serveur
Bibliothèques JavaScript pour Microsoft Dynamics CRM 2015
Article technique : Utilisation des options de groupe d’options avec le point de terminaison REST - JScript

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