• Narrow screen resolution
  • Wide screen resolution
  • Decrease font size
  • Default font size
  • Increase font size
Home arrow Newscorner arrow Microsoft Dynamics CRM arrow CRM 4.0 in Word 2007 - Teil 3 WebService
CRM 4.0 in Word 2007 - Teil 3 WebService E-Mail
Mittwoch, 23. April 2008

Im dritten Teil dieser Artikelreihe behandeln wir das Thema der Kommunikation mit Dynamics CRM. Der beste (und auch einzig supported :)) Weg ist über WebServices.

Es gibt mehrere Services, die CRM zur Verfügung stellt, wir werden uns mit dem "CrmService" WebService befassen, darüber hinaus können noch der "CrmDiscoveryService" und der "MetadataService" verwendet werden. Eine detaillierte Beschreibung dieser WebServices finden sich im SDK, kurz zusammengefasst ist der "CrmService" mein Zugang um gegen die Entitäten im CRM zu programmieren, Daten abzufragen, einzufügen, zu ändern, löschen, etc. Der "CrmDiscoveryService" hilft mir mein Installationsenvironment zu ermitteln. Da CRM 4.0 mehrinstanzenfähig ist, muss beim Ansprechen eines Service und Operieren mit Entitäten die jeweilige Organisation berücksichtigt werden.

Der "MetadataService" enthält die Daten die die Entitäten beschrieben, nicht deren Inhalt sondern deren "Aussehen", das beispielsweise durch Customizing angepasst bzw. verändert werden kann.

Konkret für das WordAddIn benötige ich den Service, um die Kundendaten und die dazugehörigen Projektdaten laden zu können.

Anmelden an den WebService

Als erstes muss der WebService instantiert werden, wofür eine Authentifizierung notwendig ist. Im SDK ist eine Klassen "CrmServiceUtility.cs" enthalten, die alle notwendigen Codezeilen hierfür enthält.

Einzige Anpassung war die Schaffung der Möglichkeit, nicht die DefaultCredentials zu verwenden (es könnte ja sein, dass der anzumeldende User nicht im CredentialCache liegt, sondern sozusagen von außerhalb über eine Form eingegeben wird). 

        public static CrmService GetCrmService(string user, string pass, string org, string server, bool useDefCreds)
        {
            CrmAuthenticationToken token = new CrmAuthenticationToken();
            token.OrganizationName = org;

            CrmService service = new CrmService();

            if (server != null && server.Length > 0)
            {
                UriBuilder builder = new UriBuilder(server);
                builder.Path = "//MSCRMServices//2007//CrmService.asmx";
                service.Url = builder.Uri.ToString();
            }

            if (useDefCreds)
            {
               ...

Die Methode benötigt im einfachsten Fall die Organisation und die Serveradresse des CRM-Servers (inklusive einem True, dass die DefaultCredentials verwendet werden sollen), im Falle einer Anmeldung über Forms noch zusätzlich den Benutzernamen und das Passwort.

Abrufen der Kundenliste und der Projektliste

Nachdem die Verbindung zum WebService errichtet wurde, können nun die Kunden abgerufen werden.

QueryExpression query = new QueryExpression();
query.EntityName = EntityName.account.ToString();
query.ColumnSet = new AllColumns();
RetrieveMultipleRequest retrieve = new RetrieveMultipleRequest();
BusinessEntityCollection results = service.RetrieveMultiple(query);

Die Kundenobjekte kommen in einer Collection zurück. Ich hab die Angewohnheit, so viele Daten wie möglich im Speicher zu halten (auch nicht immer so vorteilhaft), da das Durchsuchen ungleich schneller geht als bei ständigen Updates über den WebService.

Als nächstes wollen wir noch die zugehörigen Projekte, allerdings nicht alle, sondern die für einen bestimmten Kunden laden. Wenn man sich die GUI des WordAddIn ansieht, so erkennt man (hoffentlich :-), ich bin kein begnadeter Gui-Designer, deshalb bitte um Nachsicht), dass zuerst im PullDown-Menü ein Kunde ausgewählt wird, danach die Projekte in der ListBox angezeigt werden.

Die Suche nach den zugehörigen Projekten sieht wie folgt aus:

QueryByAttribute query = new QueryByAttribute();
query.ColumnSet = new AllColumns();
query.EntityName = EntityName.new_project.ToString();
query.Attributes = new string[] { "new_accountid" };
query.Values = new string[] { currentAccount.accountid.Value.ToString() };
BusinessEntityCollection results = service.RetrieveMultiple(query);

Übrigens, die notwendigen Informationen zu beiden Suchvarianten stammen 1:1 aus dem SDK ;-) abgeändert auf meine Bedürfnisse, sprich dem Entitätsnamen und im letzten Codeblock noch angereichert um die new_accountid, die in der Projekt-Entität die Relation zu meinem Account darstellt. Die Projekt-Entität enthält Daten wie ein Start- und Enddatum, Beschreibung, ... die notwendigen Felder (Attribute in der Entität) richten sich nach der jeweiligen Anforderung.

image

Die im Sourcecode oben gezeigte Suche verfolgt das Schema: finde alle Entitäten die "Projekt", deren Attribut "new_accountid" gleich ist dem Wert, den ich als Value übergebe und zwar ist das die AccountId meines Kunden (sozusagen seine GUID), den ich im AddIn ausgewählt habe in meiner Kundenliste. Die GUID ist generell die beste (und wohl auch einzigste :)) Variante, Datensätze von Entitäten zu finden die mit anderen Entitäten verbunden sind.

Im Endeffekt ist es immer abhängig vom Ziel, welche Entitäten ich abfrage bzw. nach welche Entitäten ich suchen möchte, aber diese Vorgehensweise hilft bei den weniger komplexen Szenarien immer weiter. Es gibt natürlich noch wesentlich umfangreichere Möglichkeiten, durch CRM zu suchen, die ich aber in diesem Blog nicht näher erläutern möchte. Anleitung dazu findet sich im SDK.

Ein paar Anmerkungen

[Threading]

Da Zugriffe, egal ob eine Anmeldung an den WebService oder eine Abfrage durchaus etwas dauern können, empfiehlt sich der Einsatz von Threads. Im WordAddIn habe ich mich dafür entschieden, eine sehr primitive Form des Threading zu verwenden, indem ich einfach die Methoden, die für die Anmeldung bzw. Abruf der Kundendaten verantwortlich sind, in einem Thread gestartet werden.

myThread = new Thread(connectToCrmService);
myThread.Start();

Man sollte halt nicht vergessen, während des Threads (der in meinem Fall ja dazu dient, Word nicht einzufrieren und nicht um parallele Abarbeitung zu ermöglichen) die Benutzereingaben zu deaktivieren oder abzufragen, ob der Thread lebt (mittels isAlive() Prüfung) um entsprechend weitere Aktionen zu lenken.

[Zugriffe auf den WebService]

Da ein WebService Zugriff immer "kostspielig" ist, sollten die Zugriffe wenn möglich vermieden werden. Wenn ich nun im Falle der Projekte nicht immer die Projekte aus dem CRM abrufen würde, sondern jedes abgerufene Projekt lokal in einer Liste zwischenhalten würde, dann wäre die maximale Anzahl der Zugriffe auf die Länge der Liste der Projekte beschränkt (ich hab das nicht gemacht :-) da im Demo die Daten nicht sehr umfangreich sind, bei vielen Daten mit vielen Referenzen macht ein Caching auf alle Fälle Sinn).

Die hier gezeigten Inhalte sind mehr oder weniger direkt aus dem CRM SDK (bis auf das Threading) bzw. aus dem Buch Visual C# 2005 (Threading) abgeleitet.

Ich hoffe, Sie konnten etwas von Interesse finden, viel Spaß beim Experimentieren.

Im nächsten Teil behandeln wir das Word Dokument, wie der Inhalt in das Word Dokument gelangt und wie ein Upload des Dokumentes ins CRM aussehen könnte.

____________________________________

Christian Hrubesch, Microsoft Dynamics


Originalartikel
 

Deutsch      English