Microsoft Dynamics CRM 2011 | XrmSvcToolkit OData – URI too long

Wie Ihr anhand zahlreicher Artikel bereits vermuten könnt, setze ich in meinen Projekten gern auf das XrmSvcToolkit. Heute möchte ich Euch auf eine Besonderheit im Zusammenhang mit der URL-Länge und der Nutzung des REST-Endpoints für OData hinweisen.

XrmSvcToolkit.retrieveMultiple({
        entityName: „Contact“,
        odataQuery: „$select=BirthDate,ContactId,CreditLimit,DoNotEMail,DoNotPhone,FamilyStatusCode,FirstName,
GenderCode,LastName,MiddleName&$filter=ContactId eq guid'“ + contactId + „‚“,
        async: false,
        successCallback: function (results) {
            // Your action
        },
        errorCallback: function (error) {
            throw error;
        }
    });

Wie Ihr dem obigen Beispiel entnehmen könnt, verwendet das Toolkit eine ODATA-Abfrage via REST-Endpoint. Einzelheiten könnt Ihr auch diesem Artikel entnehmen. In der Praxis wird die odataQuery jedoch eher dynamisch generiert.

In meinem Beispiel verwende ich SelectedControlSelectedItemIds als CRM Parameter eines ISV Buttons. Mit dessen Hilfe kann ich die IDs der ausgewählten Datensätze aus einer Listenansicht an meine Funktion übergeben.

var vtId = selectedGUIDs // entspricht einem Array aus SelectedControlSelectedItemIds

var Entity = „Contact“;
var Selection = „$select=ContactId,Address1_Line1,Address1_Line2,Address1_Line3,Address1_PostalCode,
Address1_City,Address1_Country,Address1_StateOrProvince&$filter=“;
var Filter = Filter + „ContactId eq guid'“+ vtId +“‚ or „;

Filter = Filter.substring(0,Filter.length-4);

Diese Routine durchlaufe ich in einer For-Schleife in der Anzahl Objekte in meinem Array. Bei 250 maximalen Datensätzen auf einer Listenansicht-Seite kommt man an eine Grenze, die für einen Fehler 400 (Bad Request – URI to0 long) beim Start der RetrieveMultiple-Abfrage erhält.

Der Hintergrund: Nimmt man die Anzahl der Zeichen im Filter (22) + die Anzahl einer GUID (36) und multipliziert das Ergebnis mit der maximalen Anzahl der ausgewählten Datensätze (250) kommt man auf 14.500 Zeichen. Zu diesen Zeichen gesellen sich noch die Anzahl Zeichen der URL zum OData WebService, zum EnititySet und die getroffene Selektion. Da die Server-URL bei jedem unterschiedlich sein kann, hilft folgende Abfrage zur Verdeutlichung:

var serverUrl = Xrm.Page.context.getServerUrl();

var oDataUri = serverUrl + „/xrmservices/2011/OrganizationData.svc/

Es sind also auf jeden Fall 39 Zeichen + Euer EntitySet (in meinem Beispiel ContactSet [10] + Eure Selektion (in meinem Beispiel 147) + Eure Server-URL-Länge. Wir kommen also auf einen Wert für mein Beispiel über 14.696 Zeichen.

Nun hat der IE jedoch eine maximal URL-Länge von 2.083 Zeichen, während andere Browser, wie Firefox oder Safari deutlich mehr Zeichen erlauben.

Abhilfe: Wie kann man dennoch dafür sorgen, dass auch bei 250 Datensätzen eine Abfrage möglich wird? Hier hilft eine kleine Hilfsfunktion chunk.

Array.prototype.chunk = function(chunkSize) {
    var R = [];
    for (var i=0; i<this.length; i+=chunkSize)
        R.push(this.slice(i,i+chunkSize));
    return R;
}

Mit dieser können wir unser Array [GUID1,GUID2, GUID3,…] in kleinere Array-Bereiche aufteilen. Das sieht dann in etwa so aus [[GUID1, GUID2], [GUID3, GUID4,][…]]].

Nun haben wir die Möglichkeit, die RetrieveMultiple Routine des XrmSvcToollkits mehrfach anzustoßen, da wir die odataQuery-Variable entsprechend auf unter 2.083-Zeichen reduzieren können.

Zugegeben: Schön wäre die Abfrage in einem Rutsch, da wir nunmehr natürlich auch mehrere Responses verarbeiten müssen. Dennoch ist diese einfache Variante schneller, als beispielsweise eine FetchXML-Abfrage über den SOAP-Endpoint.

Viel Spaß in der Umsetzung…

Technorati Tags:

Ein Gedanke zu “Microsoft Dynamics CRM 2011 | XrmSvcToolkit OData – URI too long

  1. Hi,

    dein Artikel ist soweit ganz gut und der Weg auch meistens umsetzbar, dennoch 2 Anmerkungen dazu:
    1) Ich habe leider schon öfter das Problem gehabt, dass sehr umfangreiche Abfragen zusammen gebaut werden mussten, die auf Grund vieler and/or-Kombinationen mit Klammern, so schwierig zu zerlegen waren, dass eigentlich nur eine SOAP-Abfrage wirklich Sinn macht.

    2) Array.prototype.chunk führt zu einem Fehler, wenn du die Library im Form für Systemuser verwendest, da Microsoft dort per „for (var x in y)“ durch die Eigenschaften von Arrays durch geht und irgendwelche Werte ermitteln will. Wir haben ähnliche Dinge mit Array.prototype.forEach und Array.prototype.reduce umgesetzt und dadurch Fehler bekommen. Außerdem dürftest du in der erweiterten Suche Fehler bekommen (der Button Ergebnisse funktioniert dann nicht mehr!), wenn du eine solche prototype-funktion in einer Library verwendest, die im Ribbon der erweiterten Suche drin ist. Ich würde also eher eine Funktion ArrayChunk(array, chunkSize) implementieren…
    Hier sollte Microsoft echt nachbessern und Schleifen mit Zählern verwenden, damit es an solchen Stellen nicht knallt, nur weil man eine Library mit prototype-Funktionen einbinden will…

    Dennoch Danke für den Artikel. Deine Posts sind tatsächlich immer sehr hilfreich!

    Gruß
    Thomas

Schreibe einen Kommentar

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s