Freigeben über


Exemplarische Vorgehensweise: Verwenden des modernen App SOAP-Endpunkts mit JavaScript

 

Veröffentlicht: November 2016

Gilt für: Dynamics CRM 2015

In dieser exemplarischen Vorgehensweise wird das Erstellen einer JavaScript-Bibliothek für die Verwendung mit dem SOAP-Endpunkt Webressourcen vorgeführt. Derzeit bietet JavaScript keine Microsoft Dynamics CRM 2015 und Microsoft Dynamics CRM Online 2015-Update-Bibliotheken, die Sie verwenden können, um Nachrichten abzurufen, die mit dem SOAP-Endpunkt verfügbar gemacht werden. In dieser exemplarischen Vorgehensweise wird gezeigt, wie Sie eine JScript-Bibliothek für die Assign-Nachricht mithilfe der Organisationdienst-Execute-Methode erstellen. Jede andere Nachricht, die die Execute-Methode verwendet, folgt einem ähnlichen Muster. Um eine JavaScript-Bibliothek für eine Nachricht zu erstellen, sind ähnlicheProzesse erforderlich. Ein Beispiel einer JavaScript-Bibliothek, die mithilfe dieses Prozesses entwickelt wurde, finden Sie unter Beispiel: Abrufen von Entitätsmetadaten mithilfe von JavaScript.

Hinweis

Eine vollständige JavaScript-Beispielbibliothek mit Verwendung des SOAP-Endpunktes finden Sie unter Sdk.Soap.js library. Die Sdk.Soap.js-Bibliothek wurde mithilfe des Prozesses erstellt, der hier beschrieben wird.

Der Prozess besteht im Erfassen derHTTP-Anforderungen und Antworten, die aus einer verwalteten Codekonsolenanwendung gesendet wurden und der folgenden Erstellung einer JavaScript-Bibliothek mit Funktionen zum Senden derselben Anforderungen Beantworten ähnlicher Anforderungen. Es ist üblich, eine Anwendung wie Fiddler zu verwenden, um HTTP-Anforderungen und Antworten zu erfassen, aber Fiddler und ähnliche Anwendungen können nicht den verschlüsselten HTTP-Datenverkehr erfassen, der für lokales Microsoft Dynamics CRM 2015 verwendet wird. Die bereitgestellte SOAPLogger-Beispiellösung erfasst die HTTP-Anforderungen, bevor sie verschlüsselt werden, und die HTTP-Antworten, nachdem sie entschlüsselt wurden. Die SOAPLogger Beispiellösung funktioniert für beide Microsoft Dynamics CRM 2015 und Microsoft Dynamics CRM Online 2015-UpdateSOAPLogger filtert auch HTTP Datenverkehr heraus, der nicht zum Erstellen einer JScript-Bibliothek relevant ist.

In dieser exemplarischen Vorgehensweise werden die folgenden Aufgaben erläutert:

  1. In Erfassungsbeispiel HHTP-Anforderung und Antwort bearbeiten Sie die Run Methode des SOAPLogger-Beispiels, um eine Assign-Anforderung unter Verwendung des verwalteten Codes durchzuführen.

  2. Dann führen Sie die SOAPLogger-Lösung aus, um Informationen zu den mit HTTP gesendeten Anforderungen und empfangenen Antworten zu generieren.

  3. In Erstellen einer JScript-Bibliothek erstellen Sie eine JScript-Bibliothek basierend auf dem erfassten HTTP-Datenverkehr, um die Assign-Nachricht unter Verwendung der Organisationsdienst-Execute-Methode zu senden und empfangen.

  4. In Testen der JScript-Bibliothek testen Sie die JScript-Bibliothek, um zu bestätigen, das sie verwendet werden kann, um Datensätze zuzuweisen.

  5. In Erstellen einer interaktiven Webressource erstellen Sie eine HTML-Webressource, die die Bibliothek verwendet, um Account-Datensätze einem ausgewählten Benutzer zuzuweisen, wie im folgenden Screenshot gezeigt.

    Seite "Konten zuweisen"

Eine verwaltete Lösung, die diese abgeschlossene exemplarische Vorgehensweise darstellt, ist im SDK-Paket unter SDK\SampleCode\JS\SOAPForJScript\SOAPEndpointforJScript_1_0_0_1_managed.zip verfügbar. Laden Sie das Microsoft Dynamics CRM SDK-Paket herunter. Sie können diese Lösung installieren (importieren) und die abgeschlossenen Ergebnisse anzeigen. Da es sich um eine verwaltete Lösung handelt, können Sie sie leicht deinstallieren (löschen), um sie vollständig aus dem System zu entfernen.

SDK\SampleCode\JS\SOAPForJScript\SOAPForJScript.sln ist eine Visual Studio-Lösung, die die HTML- und JS-Dateien mit dem Code in dieser exemplarischen Vorgehendweise enthält.

Erforderliche Komponenten

  • Sie müssen in der Lage sein, verwalteten Code zu schreiben, entsprechend den Aufgaben, die Sie mithilfe von JScript durchführen möchten.

  • Sie benötigen Zugriff auf das SOAPLogger-Beispiel, das mit den SDK-Downloaddateien unter SDK\SampleCode\CS\Client\SOAPLogger verfügbar ist.

    Hinweis

    Das SOAPLogger-Beispiel in Microsoft Dynamics CRM SDK ist nur verfügbar für Microsoft Visual C#. Wenn Sie eine Microsoft Visual Basic .NET Version bevorzugen, sehen Sie Microsoft Dynamics CRM VB.Net SoapLogger on CodePlex.

  • Sie benötigen Microsoft Visual Studio, um die SOAPLogger-Lösung auszuführen.

  • Sie müssen über gute Kenntnisse von JScript und der asynchronen Programmierung mithilfe von XMLHttpRequest verfügen.

Erfassungsbeispiel HHTP-Anforderung und Antwort

Bearbeiten Sie die SOAPLogger-Lösung, um Code hinzuzufügen, um ein AssignRequest mithilfe des SoapLoggerOrganizationService auszuführen. Das SoapLoggerOrganizationService erbt von IOrganizationService und fügt die Fähigkeit hinzu, eine Protokolldatei zu erstellen, die den relevanten gesendeten und empfangenen HTTP-Datenverkehr anzeigt.

  1. Mithilfe von Microsoft Visual Studio öffnen Sie die SOAPLogger-Lösung, die sich unter SDK\SampleCode\CS\Client\SOAPLogger\SOAPLogger.sln befindet.

  2. Suchen Sie in der Datei SoapLogger.cs die Methode Run, wie im folgenden Beispiel gezeigt:

    
    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. Ermitteln Sie gültige eine ID für einen SystemUser-Datebsatz und due ID für einen Account-Datensatz, der diesem Benutzer nicht zugewiesen ist.

    Tipp

    Wenn Sie Id aus einem Datensatz in der Anwendung erhalten, öffnen Sie den Datensatz und verwenden Sie den Befehl Link kopieren. Fügen Sie den Link in Editor ein, und isolieren Sie den Teil der den id-Parameterwert enthält, ausschließlich der kodierten Klammern (“%7b” = “{”) und (“%7d” = “}”). Beispielsweise stellt Folgendes ein URL für einen Account-Datensatz dar.<your organization root url>/main.aspx?etc=1&id=%7bF2CA52DE-552D-E011-A8FB-00155DB059BE%7d&pagetype=entityrecord>. Der ID-Wert ist F2CA52DE-552D-E011-A8FB-00155DB059BE.

    Verwenden Sie diese Werte, um die Platzhalterwerte im Code unten zu ersetzen und den Code der Ausführungsmethode hinzuzufügen, wo es angegeben ist. Weitere Informationzur "Zuweisen"-Anforderung finden Sie unter 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. Drücken Sie F5, um die Anwendung zu debuggen. Geben Sie Informationen zum Server und Ihre Authentifizierungsinformationen ein. Wenn der Code erfolgreich ausgeführt wird, wird der Firmendatensatz jetzt dem Benutzer zugewiesen, den Sie angegeben haben. Weitere Informationen zum Ausführen von Beispielcode finden Sie unter Ausführen eines einfachen Programms mit Microsoft Dynamics CRM 2015-Webdiensten

  5. Navigieren Sie in den SOAPLogger-Projektordnern zu den Ordnern bin und Debug, und suchen Sie nach der output.txt-Datei

  6. Öffnen Sie die output.txt-Datei und überprüfen Sie den Inhalt. Sie sollten etwa wie folgt aussehen, außer dass die tatsächlichen GUID-Werte den Platzhalter “XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX” ersetzen.

    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. Beachten Sie die Position der Variablen, die Sie übergaben, als Sie Ihren Code verwendeten, einschließlich des logischen Namens der Account-Entität.

Sie haben erfolgreich die relevanten Bestandteile des HTTP-Datenverkehrs erfasst, der den Zuweisensvorgang ausführte.

Erstellen einer JScript-Bibliothek

Sie können entscheiden, wie Sie eine Bibliothek im Einzelnen erstellen möchten. Jede JScript sollte die folgenden Elemente enthalten:

  • Eine Strategie, um sicherzustellen, dass der Name jeder Funktion eindeutig ist.

  • Ein Mittel, um den URL auf dem SOAP-Endpunkt für Webressourcen abzurufen.

  • Separate Methoden, mit denen die Anforderung und die Antwort asynchron gesendet und empfangen werden.

  • Eine Funktion, um zurückgegebene WCF-Fehler zu verarbeiten.

Die folgende JScript-Bibliothek enthält diese Elemente und enthält die assignRequest- und assignResponse-Funktionen zur Verwendung der Assign-Nachricht basierend auf den HTTP-Anforderungen und Antaorten, die mit SOAPLogger erfasst wurden.


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

Testen der JScript-Bibliothek

Nachdem Sie Ihre JScript-Bibliothek vorbereitet haben, sollten Sie enige Tests ausführen, um zu bestätigen, dass sie funktioniert, wie erwartet. Da Authentifizierung nur innerhalb der Anwendung auftritt, müssen Sie eine Skriptwebressource in Microsoft Dynamics CRM 2015 mithilfe der Inhalte Ihrer Bibliothek erstellen. Um die Funktionalität in der Bibliothek zu verwenden, benötigen Sie ein Benutzeroberflächenelement, entweder ein Formular oder eine HTML-Webressource, um die JScript-Funktionen in der Bibliothek aufzurufen. Im folgenden Verfahren wird die Verwendung einer einfachen HTML-Webressource beschrieben, um die Funktionalität in der Bibliothek zu testen.

  1. Erstellen Sie ein HTML-Dokument mithilfe des folgenden Codes:

    
    <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. Erstellen Sie eine HTML-Webressource mithilfe dieses Codes. Der vollständige Name der HTML-Webresource hängt vom Anpasungspräfix Ihrer Lösung ab. Wenn Ihr Lösungsanpassungspräfix "neu" ist, nennen Sie diese HTML-Webressource "new_/AssignTest.htm". Das spezifische Anpassungspräfix, das verwendet wird, hat keine Auswirkungen auf dieses Beispiel, solange alle Webressourcen dasselbe Anpassungspräfix verwenden.

  3. Erstellen Sie eine Skriptwebressource mithilfe des Inhalts der JScript-Bibliothek. Nennen Sie diese Webressource “new_/Scripts/SDK.SOAPSample.Assign.js”.

  4. Veröffentlichen Sie alle Anpassungen und öffnen Sie die new_/AssignTest.htm-Webressource. Klicken Sie auf die Schaltfläche Vorschau.

  5. Mithilfe desselben Prozesses, den Sie in Schritt drei der Prozedur No text is specified for bookmark or legacy link 'c9a435ab-a4cb-4e0c-9ef7-b7ba66278407#BKMK_EditSoapLogger'. verwendet haben, identifizieren Sie gültige System-Benutzer- und Firmen-IDs, und fügen Sie sie in die Seite ein. Klicekn Sie dann auf Test Assign , um zu bestätigen, dass Sie eine Erfolgsantwort erhalten.

  6. Geben ungültige Werte ein, um zu bestätigen, dass der Fehler richtig analysiert wird.

    Wenn Sie z. B. "Ein Laden (Beispiel)" anstelle der ID für eine Firma eingeben, sollten Sie die folgende Fehlermeldung erwarten:

    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.
    

    Wenn kein Firmendatensatz für AccountId vorhanden ist, ist die Meldung, die erwartetet wird, folgende:

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

Erstellen einer interaktiven Webressource

Der nächste Schritt ist es, Ihre JScript-Bibliothek in einem Formularskript, einem Menübandbefehl oder einer Webressource zu verwenden. Das folgende Codebeispiel stelt eine HTML-Webressource dar, die den REST-Endpunkt die verwendet, um Listen mit SystemUser- und Account-Datensätzen abzurufen, um eine interaktive Benutzerschnittstelle bereitzustellen, um Benutzern Firmendatensätze zuzuweisen. Diese Seite verwendet die Scripts/SDK.SOAPSample.Assign.js-Skriptwebressource und eine Skriptwebressource, die die json2.js-Bibliothek verwendet, um die verwendung von JSON-Objekten mit dem REST-Endpunkt zu unterstützen. Die SDK.REST.js-Bibliothek wird verwendet, um Daten unter Verwendung des REST-Endpunkts abzurufen.


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

Siehe auch

AssignRequest
Beispiel: Abrufen von Entitätsmetadaten mithilfe von JavaScript
Verwenden Sie den SOAP-Endpunkt der Modern App für moderne Anwendungen mit Webressourcen
Verwenden von Webservicedaten in Webressourcen (OData- und Modern-App-SOAP Endpunkt)
Schreiben von Anwendungen und Servererweiterungen
JavaScript-Bibliotheken für Microsoft Dynamics CRM 2015
Technischer Artikel: Verwenden von Optionssatz-Optionen mit dem REST-Endpunkt - Jscript

© 2017 Microsoft. Alle Rechte vorbehalten. Copyright