Compartir a través de


Tutorial: use el exptremo de SOAP de aplicación moderna con JavaScript

 

Publicado: noviembre de 2016

Se aplica a: Dynamics CRM 2015

Este tutorial muestra cómo crear una biblioteca de JavaScript para usarla con el extremo de SOAP con los recursos web. En este momento Microsoft Dynamics CRM 2015 y actualización de Microsoft Dynamics CRM Online 2015 no ofrece las bibliotecas de JavaScript que puede usar para recuperar los mensajes disponibles mediante el extremo de SOAP. Este tutorial muestra cómo crear una biblioteca de JScript para el mensaje de Assign mediante el método Execute de servicio de organización. Cualquier otro mensaje que utilice el método Execute seguirá un patrón similar. Para crear una biblioteca de JavaScript para cualquier mensaje requerirá un proceso similar. Para obtener un ejemplo de una biblioteca de JavaScript desarrollada mediante este proceso, consulte Ejemplo: recuperar metadatos de entidad mediante JavaScript.

Nota

Para una biblioteca de ejemplo completa de JavaScript usando el extremo SOAP, vea la biblioteca Sdk.Soap.js. La biblioteca Sdk.Soap.js se creó usando el proceso descrito aquí.

El proceso consiste en capturar las solicitudes y las respuestas HTTP enviadas de una aplicación de consola de código administrado y después crear una biblioteca de JavaScript con funciones para enviar las mismas solicitudes y procesar las respuestas similares. Es normal usar una aplicación como Fiddler para capturar las solicitudes y las respuestas HTTP pero Fiddler y las aplicaciones similares no pueden capturar el tráfico HTTP cifrado usado para Microsoft Dynamics CRM 2015 local. La solución de ejemplo SOAPLogger proporcionada captura las solicitudes HTTP antes de que se cifren y las respuestas HTTP después de que se hayan descifrado. La solución de ejemplo SOAPLogger funciona para ambos Microsoft Dynamics CRM 2015 y actualización de Microsoft Dynamics CRM Online 2015.SOAPLogger también excluye del filtro cualquier tráfico HTTP que no sea relevante para la tarea de crear una biblioteca de JScript.

Este tutorial le orienta a través de las siguientes tareas:

  1. En Ejemplo de captura de solicitud y respuesta HTTP modificará el método Run del ejemplo SOAPLogger para realizar una solicitud Assign mediante código administrado.

  2. A continuación ejecutará la solución SOAPLogger para generar la información sobre las solicitudes HTTP enviadas y las respuestas recibidas.

  3. En Cree una biblioteca de JScript creará una biblioteca de JScript basada en el tráfico HTTP capturado para enviar y recibir el mensaje de Assign mediante el método Execute del servicio de organización.

  4. En Pruebe la biblioteca de JScript probará la biblioteca de JScript para confirmar que se puede usar para asignar los registros.

  5. En Cree un recurso web interactivo creará un recurso web HTML que usa la biblioteca para asignar los registros de Account a un usuario seleccionado como se muestra en la captura de pantalla siguiente.

    Asignar página de cuentas

Tiene a su disposición una solución administrada que representa este tutorial completado en el paquete de SDK en SDK\SampleCode\JS\SOAPForJScript\SOAPEndpointforJScript_1_0_0_1_managed.zip. Descargue el paquete de SDK de Microsoft Dynamics CRM. Puede instalar (importar) la solución y ver los resultados completados. Dado que se trata de una solución administrada es muy fácil desinstalarla (eliminarla) para quitarla completamente del sistema.

SDK\SampleCode\JS\SOAPForJScript\SOAPForJScript.sln es una solución de Visual Studio que contiene los archivos HTML y JS con el código de este tutorial.

Requisitos previos

  • Debe poder escribir el código administrado correspondiente a las funciones que desea realizar mediante JScript.

  • Necesita acceso al ejemplo de SOAPLogger disponible con los archivos de descarga de SDK en SDK\SampleCode\CS\Client\SOAPLogger.

    Nota

    El ejemplo de SOAPLogger en Microsoft Dynamics CRM SDK solo está disponible para Microsoft Visual C#. Si prefiere una versión de Microsoft Visual Basic .NET, vea Microsoft Dynamics CRM VB.Net SoapLogger en CodePlex.

  • Es necesario Microsoft Visual Studio para ejecutar la solución de SOAPLogger.

  • Debe conocer bien la programación en JScript y asincrónica con XMLHttpRequest.

Ejemplo de captura de solicitud y respuesta HTTP

Modifique la solución SOAPLogger para agregar código con el fin de realizar una AssignRequest mediante SoapLoggerOrganizationService.SoapLoggerOrganizationService hereda de IOrganizationService y agrega la capacidad de generar un archivo de registro que muestra el tráfico HTTP relevante enviado y recibido.

  1. Mediante Microsoft Visual Studio, abra la solución SOAPLogger ubicada en SDK\SampleCode\CS\Client\SOAPLogger\SOAPLogger.sln.

  2. En el archivo SoapLogger.cs, busque el método Run tal como se muestra en el siguiente ejemplo:

    
    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. Identifique un id. válido para un registro SystemUser y el id. de un registro Account no asignado a dicho usuario.

    Sugerencia

    Para obtener el Id de un registro de la aplicación, abra el registro y use el comando Copiar un enlace. Pegue el enlace en Bloc de notas y aisle la parte que contiene el valor de parámetro id excepto los paréntesis con código ("%7b" = "{") y ("%7d" = "}"). Por ejemplo, lo siguiente representa una dirección URL de un registro Account.<your organization root url>/main.aspx?etc=1&id=%7bF2CA52DE-552D-E011-A8FB-00155DB059BE%7d&pagetype=entityrecord>. El valor de id. es F2CA52DE-552D-E011-A8FB-00155DB059BE.

    Use esos valores para reemplazar los valores de marcador de posición en el código siguiente y agregue el código al método run donde se indique. Para obtener más información acerca de la solicitud Assign, vea 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. Presione F5 para depurar la aplicación. Especifique la información acerca del servidor y las credenciales de autenticación. Si el código ejecuta correctamente el registro de cuenta ahora se asignará al usuario especificado. Para obtener más información acerca de cómo ejecutar el código de ejemplo, consulte Ejecutar un programa sencillo mediante los servicios web de Microsoft Dynamics CRM 2015

  5. En las carpetas de proyecto de SOAPLogger, desplácese hasta las carpetas bin y Debug y busque el archivo output.txt.

  6. Abra el archivo output.txt y revise el contenido. Deben buscar algo similar a lo siguiente a menos que los valores reales GUID reemplacen el marcador de posición "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. Tenga en cuenta la ubicación de las variables que pasó mediante el código, incluido el nombre lógico de la entidad Account.

Ha capturado correctamente las partes relevantes del tráfico HTTP que realizaron la operación de asignación.

Cree una biblioteca de JScript

Debe determinar exactamente cómo desea crear la biblioteca. Cada JScript debe tener los siguientes elementos:

  • Una estrategia para ayudar a garantizar que el nombre de cualquier función es único.

  • Un medio para recuperar la dirección URL en el extremo de SOAP para los recursos web.

  • Separar los métodos para enviar la solicitud y recibir la respuesta asincrónicamente.

  • Una función para procesar los errores de WCF devueltos.

La biblioteca de JScript siguiente incluye estos elementos e incluye las funciones assignRequest y assignResponse para usar el mensaje de Assign basándose en las las solicitudes y las respuestas HTTP capturadas mediante 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
};

Pruebe la biblioteca de JScript

Una vez que ha preparado la biblioteca de JScript debe realizar una determinada prueba inicial para confirmar que funciona según lo esperado. Ya que la autenticación solo se produce en la aplicación debe crear un recurso web de script en Microsoft Dynamics CRM 2015 mediante el contenido de la biblioteca. Para usar las funciones de la biblioteca necesitará algunos elementos de la interfaz de usuario, ya sea un formulario o un recurso web HTML para recuperar las funciones de JScript de la biblioteca. El siguiente procedimiento describe el uso de un recurso web HTML simple para probar las funciones de la biblioteca.

  1. Cree un documento HTML usando el siguiente código:

    
    <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. Cree un recurso web HTML mediante este código. El nombre completo del recurso web HTML dependerá del prefijo de personalización de la solución. Suponiendo que el prefijo de personalización de la solución es "new", ponga a este recurso web HTML el nombre de "new_/AssignTest.htm". El prefijo específico de personalización usado no tiene ningún efecto en este ejemplo siempre que todos los recursos web usen el mismo prefijo de personalización.

  3. Cree un recurso web de script mediante el contenido de la biblioteca de JScript. Ponga el nombre de "new_/Scripts/SDK.SOAPSample.Assign.js" a este recurso web.

  4. Publique todas las personalizaciones y abra el recurso web new_/AssignTest.htm. Haga clic en el botón Vista previa.

  5. Use el mismo proceso usado en el paso tres del procedimiento No text is specified for bookmark or legacy link 'c9a435ab-a4cb-4e0c-9ef7-b7ba66278407#BKMK_EditSoapLogger'., identifique los valores válidos de usuario del sistema e id. de registro de cuenta y péguelos en la página. Haga clic en Test Assign para confirmar que obtiene una respuesta correcta.

  6. Especifique valores no válidos para confirmar que el error se analiza correctamente.

    Por ejemplo, si especifica "A Store (sample)" en lugar del identificador de una cuenta debería esperar el siguiente mensaje de error:

    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.
    

    Si no existe un registro de cuenta para AccountId, el mensaje que se esperaría es:

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

Cree un recurso web interactivo

El siguiente paso es usar la biblioteca de JScript en un script de formulario, un comando de cinta de opciones o un recurso web. El siguiente ejemplo de código representa un recurso web HTML que usa el extremo de REST para recuperar las listas de registros de SystemUser y Account con el fin de proporcionar una interfaz de usuario interactiva para asignar los registros de cuenta a los usuarios. Esta página usa el recurso web de script Scripts/SDK.SOAPSample.Assign.js y un recurso web de script mediante la biblioteca json2.js para admitir el uso de objetos JSON con el extremo de REST. La biblioteca SDK.REST.js se usa para recuperar los datos mediante el extremo de 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>

Ver también

AssignRequest
Ejemplo: recuperar metadatos de entidad mediante JavaScript
Usar el extremo de SOAP de aplicaciones modernas para aplicaciones modernas con recursos web
Usar los datos del servicio web en los recursos web (extremo de SOAP para OData y aplicaciones modernas)
Escriba aplicaciones y extensiones de servidor
Bibliotecas de JavaScript para Microsoft Dynamics CRM 2015
Artículo técnico: Uso del conjunto de opciones con el extremo de REST - JScript

© 2017 Microsoft. Todos los derechos reservados. Copyright