Condividi tramite


Procedura dettagliata: utilizzare l'endpoint SOAP moderno dell'app con JavaScript

 

Data di pubblicazione: novembre 2016

Si applica a: Dynamics CRM 2015

Questa procedura dettagliata illustra la creazione di una libreria JavaScript da utilizzare con l'endpoint SOAP e le risorse Web. Al momento Aggiornamento di Microsoft Dynamics CRM 2015 e Microsoft Dynamics CRM Online 2015 non fornisce librerie JavaScript utilizzabili per chiamare i messaggi disponibili tramite l'endpoint SOAP. Nella procedura dettagliata viene indicato come creare una libreria JScript per il messaggio Assign utilizzando il metodo Execute del servizio di organizzazione. Qualsiasi altro messaggio che utilizza il metodo Execute segue un modello simile. Per creare una libreria JavaScript per qualsiasi messaggio richiederà un processo simile. Per un esempio di libreria JavaScript distribuita tramite questo processo, vedere Esempio: recuperare i metadati dell'entità utilizzando JavaScript.

Nota

Per una libreria completa JavaScript di esempio che utilizza l'endpoint SOAP, vedere la libreria Sdk.Soap.js. La libreria di Sdk.Soap.js è stata creata utilizzando il processo descritto di seguito.

Il processo include l'acquisizione delle richieste HTTP e delle risposte inviate da un'applicazione console di codice gestito e quindi la creazione di una libreria JavaScript con le funzionalità per inviare le stesse richieste ed elaborare risposte simili. Di solito si utilizza un'applicazione come Fiddler per acquisire le richieste HTTP e le risposte, ma Fiddler e le applicazioni simili non possono acquisire il traffico crittografato HTTP utilizzato per Microsoft Dynamics CRM 2015 locale. La soluzione di esempio di SOAPLogger acquisisce le richieste HTTP prima della crittografia e le risposte HTTP dopo la decrittografia. La soluzione di esempio SOAPLogger funziona per entrambi Aggiornamento di Microsoft Dynamics CRM 2015 e Microsoft Dynamics CRM Online 2015.SOAPLogger filtra inoltre il traffico HTTP non rilevante per l'attività di creazione di una libreria JScript.

Questa procedura dettagliata ti assiste nell'esecuzione delle seguenti attività:

  1. In Acquisire richiesta HTTP e risposta di esempio si modifica il metodo Run dell'esempioSOAPLogger per eseguire una richiesta Assign tramite codice gestito.

  2. Quindi si eseguirà la soluzione SOAPLogger per generare le informazioni sulle richieste HTTP inviate e sulle risposte ricevute.

  3. In Creare una libreria JScript verrà creata una libreria JScript basata sul traffico HTTP acquisito per inviare e ricevere il messaggio Assign utilizzando il metodo Execute del servizio di organizzazione.

  4. In Testare la libreria JScript verrà eseguito il test della libreria JScript per confermare che si può utilizzare per assegnare record.

  5. In Creare una risorsa Web interattiva verrà creata una risorsa Web HTML che utilizza la libreria per assegnare record Account a un utente selezionato, come illustrato nella seguente schermata.

    Pagina Assegna account

Una soluzione gestita che rappresenta la procedura dettagliata è disponibile nel pacchetto SDK in SDK\SampleCode\JS\SOAPForJScript\SOAPEndpointforJScript_1_0_0_1_managed.zip. Scarica il pacchetto SDK di Microsoft Dynamics CRM. È possibile installare (importare) la soluzione e visualizzare i risultati completati. Dal momento che è una soluzione gestita è possibile disinstallarla (eliminarla) con facilità per rimuoverla completamente dal sistema.

SDK\SampleCode\JS\SOAPForJScript\SOAPForJScript.sln è una soluzione Visual Studio contenente i file HTML e JS con il codice nella procedura dettagliata.

Prerequisiti

  • È necessario saper scrivere il codice gestito corrispondente alle funzioni che si desidera eseguire utilizzando JScript.

  • È necessario disporre dell'accesso all'esempio SOAPLogger disponibile con i file di download dell'SDK in SDK\SampleCode\CS\Client\SOAPLogger.

    Nota

    L'esempio SOAPLogger in Microsoft Dynamics CRM SDK è disponibile solo per Microsoft Visual C#. Se si preferisce una versione di Microsoft Visual Basic .NET, vedere Microsoft Dynamics CRM VB.Net SoapLogger in CodePlex.

  • È necessario Microsoft Visual Studio per eseguire la soluzione SOAPLogger.

  • È necessaria una buona conoscenza di JScript e della pianificazione asincrona mediante XMLHttpRequest.

Acquisire richiesta HTTP e risposta di esempio

Modificare la soluzione SOAPLogger per aggiungere il codice per eseguire AssignRequest utilizzando SoapLoggerOrganizationService.SoapLoggerOrganizationService eredita da IOrganizationService e aggiunge la funzionalità per generare un file di registro che indica il traffico HTTP inviato e ricevuto.

  1. Utilizzando Microsoft Visual Studio, aprire la soluzione SOAPLogger presente in SDK\SampleCode\CS\Client\SOAPLogger\SOAPLogger.sln.

  2. Nel file SoapLogger.cs, individuare il metodo Run come illustrato nel seguente esempio:

    
    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. Identificare un ID valido per il record SystemUser e l'ID di un record Account non assegnato all'utente.

    Suggerimento

    Per ottenere l'elemento Id da un record nell'applicazione, aprire il record e utilizzare il comando Copia collegamento. Incollare il collegamento in Blocco note e isolare la parte contenente il valore del parametro id escluse le parentesi codificate ("%7b" = "{") e ("%7d" = "}"). Ad esempio, di seguito è riportato un URL per un record Account.<your organization root url>/main.aspx?etc=1&id=%7bF2CA52DE-552D-E011-A8FB-00155DB059BE%7d&pagetype=entityrecord>. Il valore ID è F2CA52DE-552D-E011-A8FB-00155DB059BE.

    Utilizzare i valori per sostituire i valori segnaposto nel codice seguente e aggiungere il codice al metodo Run dove indicato. Per ulteriori informazioni sulla richiesta Assign, vedere 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. Premere F5 per eseguire il debug dell'applicazione. Immettere le informazioni sul server e le credenziali di autenticazione. Se il codice viene eseguito correttamente, il record verrà assegnato all'utente specificato. Per ulteriori informazioni sull'esecuzione del codice di esempio, vedere Eseguire un semplice programma tramite i servizi Web di Microsoft Dynamics CRM 2015

  5. Nelle cartelle di progetto di SOAPLogger, passare alle cartelle bin e Debug e cercare il file output.txt.

  6. Aprire il file output.txt ed esaminare il contenuto che sarà simile a quanto segue, ad eccezione dei valori GUID effettivi che sostituiscono il segnaposto "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. Si noti la posizione delle variabili passate tramite il codice, incluso il nome logico dell'entità Account.

Sono state correttamente acquisite le parti rilevanti del traffico HTTP che ha eseguito l'operazione di assegnazione.

Creare una libreria JScript

La scelta della modalità da utilizzare per costruire la libreria dipende dall'utente. Ogni JScript deve disporre degli elementi seguenti:

  • Una strategia per essere certi che il nome di ogni funzione sia univoco.

  • Risorse per recuperare l'URL dell'endpoint SOAP per le risorse Web.

  • Separare i metodi per inviare la richiesta e la ricezione la risposta in modalità asincrona.

  • Una funzione per elaborare gli errori WCF restituiti.

La seguente libreria JScript include gli elementi e le funzioni assignResponse e assignRequest per utilizzare il messaggio Assign in base alle richieste HTTP e alle risposte acquisite utilizzando 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
};

Testare la libreria JScript

Dopo aver preparato la libreria JScript è necessario eseguire alcuni test iniziali per confermare che funziona come previsto. Poiché l'autenticazione viene eseguita solo nell'applicazione, è necessario creare una risorsa Web script in Microsoft Dynamics CRM 2015 utilizzando il contenuto della libreria. Per utilizzare le funzionalità della libreria è necessario disporre di un elemento dell'interfaccia utente, un modulo o una risorsa WEb HTML per chiamare le funzioni JScript nella libreria. La procedura seguente indica l'utilizzo di una risorsa Web semplice HTML per testare le funzioni nella libreria.

  1. Creare un documento HTML utilizzando il codice seguente:

    
    <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. Creare una risorsa Web HTML utilizzando questo codice. Il nome completo della risorsa Web HTML dipende dal prefisso di personalizzazione della soluzione. Presumendo che il prefisso di personalizzazione della soluzione sia "new", il nome della risorsa Web HTML è "new_/AssignTest.htm". Il prefisso di personalizzazione specifico utilizzato non influisce in questo esempio perché tutte le risorse Web utilizzano lo stesso prefisso di personalizzazione.

  3. Creare una risorsa Web script utilizzando il contenuto della libreria JScript. Assegnare alla risorsa Web il nome "new_/Scripts/SDK.SOAPSample.Assign.js".

  4. Pubblicare tutte le personalizzazioni e aprire la risorsa Web new_/AssignTest.htm. Fare clic sul pulsante Anteprima.

  5. Utilizzando lo stesso processo del terzo passaggio della procedura No text is specified for bookmark or legacy link 'c9a435ab-a4cb-4e0c-9ef7-b7ba66278407#BKMK_EditSoapLogger'., individuare i valori validi di ID record account e ID utente di sistema e incollarli nella pagina. Quindi fare clic su Test Assign per confermare di aver ricevuto una risposta corretta.

  6. Immettere i valori non validi per confermare che l'errore viene analizzato correttamente.

    Ad esempio, se si immette "Archivio (esempio)" anziché l'ID di un account, verrà visualizzato il messaggio di errore seguente:

    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.
    

    Se non è presente un record di account per AccountId, il messaggio è:

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

Creare una risorsa Web interattiva

Il prossimo passaggio consiste nell'utilizzare la libreria JScript in uno script di modulo, un comando della barra multifunzione o una risorsa Web. Il seguente esempio di codice rappresenta una risorsa Web HTML che utilizza l'endpoint REST per recuperare elenchi di record SystemUser e Account per fornire un'interfaccia utente interattiva per assegnare i record di account agli utenti. In questa pagina viene utilizzata la risorsa Web script Scripts/SDK.SOAPSample.Assign.js e una risorsa Web script mediante la libreria json2.js per supportare l'utilizzo di oggetti JSON con l'endpoint REST. La libreria SDK.REST.js viene utilizzata per recuperare i dati tramite l'endpoint 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>

Vedere anche

AssignRequest
Esempio: recuperare i metadati dell'entità utilizzando JavaScript
Utilizzare l'endpoint SOAP applicazioni moderne per applicazioni moderne con risorse Web
Utilizzare i dati del servizio Web nelle risorse Web (OData ed endpoint SOAP moderno dell'app)
Scrivere applicazioni ed estensioni del server
Librerie JavaScript per Microsoft Dynamics CRM 2015
Articolo tecnico: Utilizzo delle opzioni Set di opzioni con l'endpoint REST - JScript

© 2017 Microsoft. Tutti i diritti sono riservati. Copyright