Verwenden des verwalteten Clientobjektmodells von SharePoint Foundation 2010

Zusammenfassung:   Informationen dazu, wie Sie mit dem verwalteten Clientobjektmodell von SharePoint Foundation 2010 Anwendungen schreiben, die auf .NET Framework basieren und von Clients aus auf SharePoint-Inhalte zugreifen, ohne dass auf dem Server mit SharePoint Foundation 2010 Code installiert werden muss.

Letzte Änderung: Montag, 9. März 2015

Gilt für: Business Connectivity Services | Office 2010 | Open XML | SharePoint Designer 2010 | SharePoint Foundation 2010 | SharePoint Online | SharePoint Server 2010 | Visual Studio

Inhalt dieses Artikels
Übersicht
Verwenden des verwalteten Clientobjektmodells von SharePoint Foundation 2010
Funktionsweise des clientseitigen Objektmodells
Erstellen von über die Windows-Konsole verwalteten Clientobjektmodell-Anwendungen
Übersicht über das verwaltete Clientobjektmodell von SharePoint Foundation 2010
Verwenden von Objektidentitäten
Einschränken von Resultsets
Erstellen und Auffüllen von Listen
Verwenden von Collaborative Application Markup Language (CAML) zum Durchführen von Abfragen in Listen
Filtern der untergeordneten Auflistung, die von der "Load"-Methode zurückgegeben wird, mithilfe von "LINQ"
Verwenden der "LoadQuery"-Methode
Steigern der Leistung durch Schachteln von "Include"-Anweisungen in der "LoadQuery"-Methode
Filtern der untergeordneten Auflistung, die von der "LoadQuery"-Methode zurückgegeben wird, mithilfe von "LINQ"
Aktualisieren von Clientobjekten
Löschen von Clientobjekten
Ermitteln des Schemas für Felder
Zugreifen auf umfangreiche Listen
Asynchrone Verarbeitung
Weitere Ressourcen

Beitrag von:  Eric White, Microsoft Corporation

Inhalt

  • Übersicht

  • Verwenden des verwalteten Clientobjektmodells von SharePoint Foundation 2010

  • Funktionsweise des clientseitigen Objektmodells

  • Erstellen von über die Windows-Konsole verwalteten Clientobjektmodell-Anwendungen

  • Übersicht über das verwaltete Clientobjektmodell von SharePoint Foundation 2010

  • Verwenden von Objektidentitäten

  • Einschränken von Resultsets

  • Erstellen und Auffüllen von Listen

  • Verwenden von Collaborative Application Markup Language (CAML) zum Durchführen von Abfragen in Listen

  • Filtern der untergeordneten Auflistung, die von der "Load"-Methode zurückgegeben wird, mithilfe von "LINQ"

  • Verwenden der "LoadQuery"-Methode

  • Steigern der Leistung durch Schachteln von "Include"-Anweisungen in der "LoadQuery"-Methode

  • Filtern der untergeordneten Auflistung, die von der "LoadQuery"-Methode zurückgegeben wird, mithilfe von "LINQ"

  • Aktualisieren von Clientobjekten

  • Löschen von Clientobjekten

  • Ermitteln des Schemas für Felder

  • Zugreifen auf umfangreiche Listen

  • Asynchrone Verarbeitung

  • Weitere Ressourcen

Übersicht

Mit dem verwalteten Clientobjektmodell von SharePoint Foundation 2010 können Sie Clientanwendungen entwickeln, die auf SharePoint-Inhalte zugreifen, ohne dass Sie Code auf dem Server installieren müssen, auf dem Microsoft SharePoint Foundation 2010 ausgeführt wird. Beispielsweise können Sie neue Anwendungskategorien erstellen, etwa Anwendungen auf der Basis von Microsoft .NET Framework, anspruchsvolle interaktive Webparts, Microsoft Silverlight-Anwendungen und ECMAScript (JavaScript, JScript)-Anwendungen, die clientseitig in einem SharePoint-Webpart ausgeführt werden. Im Folgenden einige Beispiele:

  • Eine Teamleiterin erstellt eine SharePoint-Website, die zahlreiche Listen beinhaltet, die für die Koordination der Aufgabe ihres Teams benötigt werden. Sie möchte, dass diese Listen ad hoc geändert werden können, z. B. indem Zuweisungen und Schätzungen auf der Basis einer Open XML-Kalkulationstabelle geändert oder Elemente von einer SharePoint-Liste in eine andere verschoben werden. Zu diesem Zweck möchte sie eine kleine benutzerdefinierte Anwendung schreiben.

  • Ein Softwareunternehmen, das eine traditionelle, umfangreiche Clientanwendung anbietet, möchte SharePoint-Dokumentbibliotheken und -Listen in seine Anwendung integrieren. Die Integration soll nahtlos sein, d. h. für die Benutzer unsichtbar.

  • Ein SharePoint-Entwickler möchte ein anspruchsvolles Webpart für eine SharePoint-Bereitstellung erstellen, das Listeninhalte in den benutzerdefinierten AJAX-Webcode des Unternehmens konvertiert. Außerdem möchte er eine noch leistungsfähigere Silverlight-Anwendung entwickeln, die die gleiche Funktion erfüllt.

Welche Gemeinsamkeit haben diese Aufgabenstellungen? In allen drei Fällen können die Entwickler das verwaltete Clientobjektmodell von SharePoint Foundation 2010 verwenden, um das Problem zu lösen. Mit dem verwalteten Clientobjektmodell von SharePoint Foundation 2010 können Sie clientseitigen Code schreiben, der alle gängigen Objekte in SharePoint-Websites verwendet. Mithilfe des Objektmodells können Sie Listen hinzufügen und entfernen, Listenelemente hinzufügen, aktualisieren und löschen, Dokumente in Dokumentbibliotheken ändern, Websites erstellen, Berechtigungen für Elemente verwalten und Webparts auf einer Seite hinzufügen oder entfernen.

Früher gab es weniger Möglichkeiten. Man konnte Webdienste für die Interaktion mit SharePoint-Listen und anderen Features verwenden, doch das war eine Herausforderung. Wenn die Webdienste nicht die erforderlichen Funktionen bereitstellten, konnte man serverseitigen Code schreiben, um einen neuen Webdienst bereitzustellen (was noch schwieriger war). In manchen IT-Abteilungen ist serverseitiger Code nicht zulässig, oder es ist nur Code erlaubt, der von der IT-Abteilung entwickelt wurde. Diese Möglichkeit bestand also auch nicht immer. Das verwaltete Clientobjektmodell von SharePoint Foundation 2010 ermöglicht nun neue Arten von Anwendungen und vereinfacht das Schreiben von clientseitigem Code, der mit SharePoint-Inhalten interagiert.

Verwenden des verwalteten Clientobjektmodells von SharePoint Foundation 2010

Wenn Sie das verwaltete Clientobjektmodell von SharePoint Foundation 2010 (Clientobjektmodell) nutzen, schreiben Sie auf .NET Framework basierenden verwalteten Code, der eine API verwendet, die dem auf einem Server mit SharePoint Foundation verwendeten Objektmodell ähnelt. Das Clientobjektmodell enthält Klassen für den Zugriff auf Websitesammlungsinformationen, Websiteinformationen sowie Listen- und Listenelementinformationen.

Im Falle von Webparts verwenden Sie eine ECMAScript (JavaScript, JScript)-Programmierschnittstelle, die der .NET Framework-API ähnelt. Für Silverlight verwenden Sie eine Teilmenge der API, die über .NET Framework auf dem Client zur Verfügung steht. Ein großer Teil der Informationen in diesem Artikel betrifft die JavaScript- und die Silverlight-API. Schwerpunkt dieses Artikels ist jedoch die Verwendung des verwalteten Clientobjektmodells von SharePoint Foundation 2010 von einer Clientanwendung aus, die auf .NET Framework basiert.

Das verwaltete Clientobjektmodell von SharePoint Foundation 2010 besteht aus zwei Assemblys, die fünf Namespaces enthalten. Wenn Sie diese Namespaces einmal betrachten, sehen Sie eine große Zahl von Klassen. Lassen Sie sich davon nicht beeindrucken – viele dieser Klassen werden nur intern vom Objektmodell verwendet. Sie benötigen nur einen Teil dieser Klassen, nämlich überwiegend Klassen, die ein direktes Gegenstück zu gängigen Klassen im Serverobjektmodell von SharePoint Foundation sind.

Tabelle 1. Clientseitige Klassen und ihre serverseitigen Entsprechungen

Client

Server

ClientContext

SPContext

Site

SPSite

Web

SPWeb

List

SPList

ListItem

SPListItem

Field

SPField

Wie Sie sehen, wird im verwalteten Clientobjektmodell von SharePoint Foundation 2010 das gleiche bisherige Benennungsschema für Websitesammlungen und Websites verwendet wie für das Serverobjektmodell. Die Site-Klasse stellt Websitesammlungen dar, die Web-Klasse Websites. Ich benenne bei der Verwendung dieser Klassen vorzugsweise die Variablen so, dass der Variablenname darauf hinweist, ob es sich um eine Websitesammlung oder eine Website handelt, auch wenn die Variablen mit der Site- und der Web-Klasse deklariert werden müssen.

Das folgende Beispiel zeigt, wie ich Variablen benenne.

ClientContext clientContext = new ClientContext(siteUrl);
Site siteCollection = clientContext.Site;
Web site = clientContext.Web;

Funktionsweise des clientseitigen Objektmodells

Eine Anwendung, die SharePoint-Inhalte verwendet, interagiert auf vielfältige Weise mit der API: Methoden werden aufgerufen, Rückgabewerte abgerufen, Collaborative Application Markup Language (CAML)-Abfragen werden übergeben und die Ergebnisse abgerufen, und Eigenschaften werden festgelegt oder abgerufen. Nachdem Sie die API zum Ausführen einer bestimmten Aufgabe verwendet haben, bündelt das verwaltete Clientobjektmodell von SharePoint Foundation 2010 diese Verwendungen der API in XML und sendet sie an den Server, auf dem SharePoint Foundation ausgeführt wird. Der Server empfängt diese Anforderung, führt entsprechende Aufrufe des Objektmodells auf dem Server durch, sammelt die Antworten, konvertiert sie in JavaScript Object Notation (JSON) und sendet den JSON-Code an das verwaltete Clientobjektmodell von SharePoint Foundation 2010 zurück. Das Clientobjektmodell analysiert den JSON-Code und übergibt der Anwendung die Ergebnisse als .NET Framework-Objekte (bzw. für JavaScript als JavaScript-Objekte). Das folgende Diagramm veranschaulicht die einzelnen Schritte dieser Interaktion.

Abbildung 1. Das verwaltete Clientobjektmodell von SharePoint Foundation 2010

0ebaeb17-ceb2-43a7-9ebe-22adc04b6137

Beachten Sie, dass Sie steuern, wann das verwaltete Clientobjektmodell von SharePoint Foundation 2010 den XML-Code an den Server sendet und den JSON-Code vom Server zurück erhält.

Die Bündelung mehrerer Methodenaufrufe zu einem einzigen Aufruf an den Server wird durch die Netzwerkgeschwindigkeit, die Netzwerklatenz und die gewünschten Leistungseigenschaften bestimmt. Würde das verwaltete Clientobjektmodell von SharePoint Foundation 2010 bei jedem Methodenaufruf mit dem Server interagieren, würde dies die Leistung des Systems stark beeinträchtigen, und das System wäre aufgrund des erhöhten Netzwerkverkehrs nicht mehr handhabbar.

Wie also bereits erwähnt, steuern Sie explizit, wann das verwaltete Clientobjektmodell von SharePoint Foundation 2010 Methodenaufrufe bündelt und eine Anforderung an den Server sendet. Dementsprechend müssen Sie, bevor die Interaktion mit dem Server beginnt, explizit festlegen, welche Inhalte Sie vom Server abrufen möchten. Dies ist der Hauptunterschied zwischen dem verwalteten Clientobjektmodell von SharePoint Foundation 2010 und dem SharePoint Foundation 2010-Objektmodell. Wenn Sie das Modell einmal verstanden haben, ist das für Sie kein Problem mehr. Am einfachsten können Sie sich den Unterschied klarmachen, indem Sie eine einfache Anwendung betrachten.

Erstellen von über die Windows-Konsole verwalteten Clientobjektmodell-Anwendungen

HinweisHinweis

Ich verwende Windows-Konsolenanwendungen für den Beispielcode. Sie können die gleiche Vorgehensweise jedoch auch für andere Anwendungstypen verwenden.

Zum Erstellen der Anwendung müssen Sie zwei Assemblys, Microsoft.SharePoint.Client.dll und Microsoft.SharePoint.Client.Runtime.dll, Verweise hinzufügen. Durch Installation von SharePoint Foundation werden diese beiden Assemblys auf dem Server installiert. Die zwei Assemblys befinden sich in folgendem Verzeichnis:

%ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\ISAPI

Wichtiger HinweisWichtig

Für SharePoint Foundation Beta und Microsoft SharePoint Server 2010 Beta müssen Sie die beiden Assemblys kopieren und in einem geeigneten Verzeichnis auf Ihrem Clientcomputer für die Entwicklung ablegen. Sie müssen zu diesen Assemblys navigieren, um ihnen Verweise hinzuzufügen, wenn Sie Projekte einrichten, bei denen das verwaltete Clientobjektmodell von SharePoint Foundation 2010 verwendet wird.

So erstellen Sie die Anwendung

  1. Starten Sie Microsoft Visual Studio 2010.

  2. Zeigen Sie im Menü Datei auf Neu, und klicken Sie auf Projekt.

  3. Erweitern Sie im Dialogfeld Neues Projekt im Bereich Zuletzt verwendete Vorlagen den Eintrag Visual C#, und klicken Sie dann auf Windows.

  4. Klicken Sie rechts vom Bereich Zuletzt verwendete Vorlagen auf Konsolenanwendung.

  5. Standardmäßig wird in Visual Studio ein Projekt erstellt, das .NET Framework 4 als Ziel hat. Sie müssen jedoch .NET Framework 3.5 als Ziel angeben. Wählen Sie in der Liste im oberen Teil des Dialogfelds Datei öffnen den Eintrag .NET Framework 3.5.

  6. Geben Sie im Feld Name den gewünschten Namen für das Projekt ein, etwa FirstClientApiApplication.

  7. Geben Sie im Feld Speicherort den Speicherort für das Projekt ein.

    Abbildung 2. Erstellen einer Lösung im Dialogfeld Neues Projekt

    6fff7a0d-bf31-4042-acb2-72a16fce6e19

  8. Klicken Sie auf OK, um die Lösung zu erstellen.

So fügen Sie der Microsoft.SharePoint.Client- und der Microsoft.SharePoint.Client.Runtime-Assembly Verweise hinzu

  1. Die Klassen, die Sie in einer Clientobjektmodell-Anwendung verwenden, befinden sich in Microsoft.SharePoint.Client.dll und Microsoft.SharePoint.Client.Runtime.dll. Wie ich bereits erwähnte, müssen Sie diese Assemblys vor dem Hinzufügen der Verweise von dem Server, auf dem SharePoint Foundation ausgeführt wird, auf den Clientcomputer für die Entwicklung kopieren.

  2. Klicken Sie im Menü Projekt auf Verweis hinzufügen, um das Dialogfeld Verweis hinzufügen zu öffnen.

  3. Klicken Sie auf die Registerkarte Durchsuchen, navigieren Sie zu dem Speicherort, an dem Sie die DLLs Microsoft.SharePoint.Client.dll und Microsoft.SharePoint.Client.Runtime.dll ablegen möchten. Wählen Sie beide DLLs aus, und klicken Sie auf OK, wie in Abbildung 3 gezeigt.

    Abbildung 3. Hinzufügen von Verweisen zu den Assemblys

    820cc11d-ae55-4acb-9cf5-8272117ce0df

So fügen Sie der Lösung den Beispielcode hinzu

  1. Ersetzen Sie in Visual Studio den Inhalt der Quelldatei Program.cs durch den folgenden Code.

    using System;
    using Microsoft.SharePoint.Client;
    
    class DisplayWebTitle
    {
        static void Main()
        {
            ClientContext clientContext = new ClientContext("http://intranet.contoso.com");
            Web site = clientContext.Web;
            clientContext.Load(site);
            clientContext.ExecuteQuery();
            Console.WriteLine("Title: {0}", site.Title);
        }
    }
    
  2. Ersetzen Sie die URL im ClientContext(String)-Konstruktor durch die URL zur SharePoint-Website. Erstellen Sie die Lösung, und führen Sie sie aus. Im Beispiel wird der Titel der Website gedruckt.

Genau wie beim Serverobjektmodell von SharePoint Foundation erstellen Sie einen Kontext für die SharePoint-Website, auf die Sie zugreifen möchten. Anschließend können Sie einen Verweis auf die Website aus dem Kontext abrufen.

Der Aufruf der ExecuteQuery()-Methode bewirkt, dass das verwaltete Clientobjektmodell von SharePoint Foundation 2010 die Anforderung an den Server sendet. Es entsteht kein Netzwerkverkehr, bis die Anwendung die ExecuteQuery()-Methode aufruft.

Ein wichtiger Punkt bei diesem Beispiel ist, dass durch den Aufruf der Load()-Methode eigentlich nichts geladen wird. Vielmehr wird hiermit das Clientobjektmodell darüber informiert, dass Sie, wenn die Anwendung die ExecuteQuery()-Methode aufruft, die Eigenschaftenwerte des siteCollection-Objekts laden möchten.

Dies ist das Modell, das für alle Interaktionen mit dem Server erforderlich ist:

  1. Sie teilen dem verwalteten Clientobjektmodell von SharePoint Foundation 2010 mit, welche Vorgänge Sie ausführen möchten. Dazu gehören der Zugriff auf die Werte der Eigenschaften von Objekten (z. B. Objekte der List-, ListItem- und Web-Klasse), CAML-Abfragen, die Sie ausführen möchten, und Objekte wie ListItem-Objekte, die Sie einfügen, aktualisieren oder löschen möchten.

  2. Anschließend rufen Sie die ExecuteQuery()-Methode auf. Es entsteht kein Netzwerkverkehr, bis Sie die ExecuteQuery()-Methode aufrufen. Bis zu diesem Punkt registriert die Anwendung lediglich ihre Anforderungen.

Wie Sie aus diesem Beispiel ersehen, definieren Sie im einfachsten Fall zuerst eine Abfrage und führen dann die Abfragen aus. Dadurch sendet das Clientobjektmodell Daten an den Server und erhält von diesem eine Antwort. Im nächsten Abschnitt wird das Modell ausführlich erklärt. Außerdem erfahren Sie, warum es so konzipiert ist und wie Sie damit Anwendungen erstellen können.

Übersicht über das verwaltete Clientobjektmodell von SharePoint Foundation 2010

Mit bestimmten Aspekten des Clientobjektmodells sollten Sie sich vertraut machen:

  • Strategien des Clientobjektmodells zur Minimierung des Netzwerkverkehrs

  • Erstellen einer Abfrage

  • Techniken zur Verbesserung der Serverleistung

  • Erstellen, Aktualisieren und Löschen von Clientobjekten

  • Arbeiten mit sehr umfangreichen Listen

Bevor wir uns jedoch in eines dieser Themen vertiefen, wollen wir uns mit Objektidentitäten befassen.

Verwenden von Objektidentitäten

Der Kerngedanke der Objektidentität ist, dass Clientobjekte sowohl vor als auch nach dem Aufrufen der ExecuteQuery()-Methode auf das entsprechende Objekt im SharePoint Foundation-Serverobjektmodell verweisen. Sie verweisen durch mehrere Aufrufe der ExecuteQuery()-Methode weiterhin auf das gleiche Objekt.

Das bedeutet, dass das Clientobjektmodell beim Erstellen der Abfrage Objekte zurückgibt, die Sie zur weiteren Festlegung der Abfrage verwenden können, bevor Sie die ExecuteQuery()-Methode aufrufen. Dadurch können Sie komplexere Abfragen schreiben, ohne dass dadurch zunächst mehr Netzwerkverkehr zum und vom Server entsteht. Sie können anspruchsvollere Vorgänge in einer einzigen Abfrage ausführen und dabei Netzwerkverkehr vermeiden.

Im folgenden Beispiel wird das Announcements -Listenobjekt abgerufen, anschließend werden alle Elemente dieser Liste mithilfe der einfachsten CAML-Abfrage abgerufen.

using System;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main()
    {
        ClientContext clientContext = new ClientContext("http://intranet.contoso.com");
        List list = clientContext.Web.Lists.GetByTitle("Announcements");
        CamlQuery camlQuery = new CamlQuery();
        camlQuery.ViewXml = "<View/>";
        ListItemCollection listItems = list.GetItems(camlQuery);
        clientContext.Load(list);clientContext.Load(listItems);
        clientContext.ExecuteQuery();
        foreach (ListItem listItem in listItems)
            Console.WriteLine("Id: {0} Title: {1}", listItem.Id, oListItem["Title"]);
    }
}

Beachten Sie die Reihenfolge in diesem Beispiel:

  1. Zuerst ruft der Code ein List-Objekt mithilfe der GetByTitle()-Methode ab. Denken Sie daran, dass dieses List-Objekt keine Daten enthält. Es enthält erst dann Daten in seinen Eigenschaften, wenn die Anwendung die ExecuteQuery()-Methode aufruft.

  2. Anschließend ruft der Code die GetItems()-Methode für das list-Objekt auf, obwohl dieses list-Objekt nicht mit Daten aufgefüllt ist.

  3. Schließlich ruft der Code die Load()-Methode sowohl für das list-Objekt als auch für das listItems-Objekt und danach die ExecuteQuery()-Methode auf.

Der springende Punkt hierbei ist, dass das Clientobjektmodell sich sozusagen daran "erinnert", dass das list-Objekt mithilfe der GetByTitle()-Methode von der Anwendung initialisiert wurde, und dass das Clientobjektmodell die CAML-Abfrage für genau dieses list-Objekt ausführen soll, nachdem das list-Objekt aus der SharePoint-Datenbank abgerufen wurde. Jede von der ClientObject-Klasse abgeleitete Klasse weist diese Semantik auf.

Wie ich schon erwähnte, können Sie nach dem Aufrufen der ExecuteQuery()-Methode weiterhin Clientobjekte verwenden, um zusätzliche Abfragen zu erstellen. Im folgenden Beispiel lädt der Code das list-Objekt und ruft die ExecuteQuery()-Methode auf. Anschließend ruft er mithilfe dieses list-Clientobjekts die List.GetItems-Methode auf und danach erneut die ExecuteQuery()-Methode. Das list-Objekt hat seine Identität durch den Aufruf der ExecuteQuery()-Methode beibehalten.

using System;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main()
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        List list = clientContext.Web.Lists
            .GetByTitle("Announcements");
        clientContext.Load(list);
        clientContext.ExecuteQuery();
        Console.WriteLine("List Title: {0}", list.Title);
        CamlQuery camlQuery = new CamlQuery();
        camlQuery.ViewXml = "<View/>";
        ListItemCollection listItems = list.GetItems(camlQuery);
        clientContext.Load(listItems);
        clientContext.ExecuteQuery();
        foreach (ListItem listItem in listItems)
            Console.WriteLine("Id: {0} Title: {1}",
                oListItem.Id, listItem["Title"]);
    }
}

Manche Eigenschaften und Methoden geben Objekte oder Werttypen zurück, die nicht von der ClientObject-Klasse abgeleitet sind. Die Vorteile der Verwendung der Clientobjektidentität für den Zugriff auf Methoden und Eigenschaften können Sie nur nutzen, wenn diese Methoden und Eigenschaften Clientobjekte oder Auflistungen von Clientobjekten zurückgeben. Beispielsweise leiten sich bestimmte Klassen, etwa die FieldUrlValue- und die FieldLookupValue-Klasse, von der ClientValueObject-Klasse ab, und Sie können Eigenschaften, die diese Typen zurückgeben, erst nach dem Aufruf der ExecuteQuery()-Methode verwenden. Manche Eigenschaften geben .NET Framework-Typen zurück, z. B. string oder integer, und Sie können Eigenschaften oder Methoden, die diese Typen zurückgeben, auch erst nach dem Aufruf der ExecuteQuery()-Methode verwenden. Da Sie die Werte von Eigenschaften nicht verwenden können, bevor diese Werte im ExecuteQuery()-Aufruf aufgefüllt wurden, ist es beispielsweise nicht möglich, ein Element in einer Liste zu finden und den Wert eines der Felder dieses Elements zum Auswählen von Elementen in einer zusätzlichen Abfrage zu verwenden. Wenn Sie versuchen, eine Eigenschaft zu verwenden, bevor sie durch die ExecuteQuery()-Methode aufgefüllt wurde, löst das Clientobjektmodell eine PropertyOrFieldNotInitializedException-Ausnahme aus.

VorsichtVorsicht

Die Clientobjektidentität gilt nur für ein einziges ClientContext-Objekt. Wenn Sie ein weiteres ClientContext-Objekt für die gleiche SharePoint-Website initialisieren, können Sie Clientobjekte aus einem Clientkontext nicht für den anderen Clientkontext verwenden.

Bei einigen Beispielen weiter unten in diesem Artikel wird das Objektidentitätsverhalten genutzt.

HinweisHinweis

In diesem Beispiel erfolgt keine Fehlerbehandlung. Wenn die Announcements -Liste nicht vorhanden ist, löst das Clientobjektmodell im Aufruf der ExecuteQuery()-Methode eine Ausnahme aus. Wenn Sie Code schreiben, bei dem u. U. Fehler auftreten, wenn Sie Objekte anfordern, die nicht vorhanden sind, können Ausnahmen auftreten.

Einschränken von Resultsets

SharePoint Foundation wird häufig in Organisationen mit vielen Tausenden Benutzern bereitgestellt. Beim Erstellen einer Anwendung, die über das Netzwerk auf SharePoint Foundation zugreift, ist es sinnvoll, darauf zu achten, dass möglichst wenig Netzwerkverkehr entsteht. Das Clientobjektmodell unterstützt Sie dabei auf vielfache Weise. Die einfachste Möglichkeit besteht darin, mithilfe von Lambda-Ausdrücken genau anzugeben, welche Eigenschaften das Clientobjektmodell an die Anwendung zurückgeben soll.

Das folgende Beispiel zeigt, wie Sie angeben, dass das Clientobjektmodell beim Laden des Websiteobjekts nur die Title- und die Description-Eigenschaft laden soll. Dadurch wird der Umfang der JSON-Antwort vom Server an den Client reduziert.

using System;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main()
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        Web site = clientContext.Web;
        clientContext.Load(site,
            s => s.Title,
            s => s.Description);
        clientContext.ExecuteQuery();
        Console.WriteLine("Title: {0} Description: {1}",
            site.Title, site.Description);
    }
}

Wenn Sie diese Lambda-Ausdrücke nicht in den Aufruf der Load()-Methode einfügen, wird standardmäßig eine viel größere Zahl von Eigenschaften geladen (jedoch nicht alle). In den beiden ersten Beispielen wurde die Load()-Methode aufgerufen, ohne dass angegeben wurde, welche Eigenschaften geladen werden sollen. Daher war das vom Server zurückgegebene JSON-Paket größer, als eigentlich notwendig wäre. In diesen kleinen Beispielen macht das keinen großen Unterschied. Beim Laden von Tausenden von Listenelementen können Sie jedoch durch sorgfältiges Angeben der benötigten Eigenschaften den Netzwerkverkehr eindämmen.

Mithilfe von Lambda-Ausdrücken können Sie eine Liste der Eigenschaften für die Load()-Methode angeben. Verringerter Netzwerkverkehr ist nicht der einzige Vorteil, den der Einsatz von Lambda-Ausdrücken im Clientobjektmodell bringt. Weiter unten in diesem Artikel erfahren Sie, wie Sie Resultsets mithilfe von Lambda-Ausdrücken filtern können.

Als Nächstes zeige ich ein Beispiel, in dem eine Liste erstellt wird, der dann einige Inhalte hinzugefügt werden. Dadurch werden Beispielinhalte erstellt, mit denen wir in den verbleibenden Abschnitten des Artikels arbeiten können.

Erstellen und Auffüllen von Listen

Im folgenden Beispiel wird eine Liste erstellt, der dann einige Felder und Elemente hinzugefügt werden.

using System;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main()
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        Web site = clientContext.Web;

        // Create a list.
        ListCreationInformation listCreationInfo =
            new ListCreationInformation();
        listCreationInfo.Title = "Client API Test List";
        listCreationInfo.TemplateType = (int)ListTemplateType.GenericList;
        List list = site.Lists.Add(listCreationInfo);

        // Add fields to the list.
        Field field1 = list.Fields.AddFieldAsXml(
            @"<Field Type='Choice'
                     DisplayName='Category'
                     Format='Dropdown'>
                <Default>Specification</Default>
                <CHOICES>
                  <CHOICE>Specification</CHOICE>
                  <CHOICE>Development</CHOICE>
                  <CHOICE>Test</CHOICE>
                  <CHOICE>Documentation</CHOICE>
                </CHOICES>
              </Field>",
            true, AddFieldOptions.DefaultValue);
        Field field2 = list.Fields.AddFieldAsXml(
            @"<Field Type='Number'
                     DisplayName='Estimate'/>",
            true, AddFieldOptions.DefaultValue);

        // Add some data.
        ListItemCreationInformation itemCreateInfo =
            new ListItemCreationInformation();
        ListItem listItem = list.AddItem(itemCreateInfo);
        listItem["Title"] = "Write specs for user interface.";
        listItem["Category"] = "Specification";
        listItem["Estimate"] = "20";
        listItem.Update();

        listItem = list.AddItem(itemCreateInfo);
        listItem["Title"] = "Develop proof-of-concept.";
        listItem["Category"] = "Development";
        listItem["Estimate"] = "42";
        listItem.Update();
        
        listItem = list.AddItem(itemCreateInfo);
        listItem["Title"] = "Write test plan for user interface.";
        listItem["Category"] = "Test";
        listItem["Estimate"] = "16";
        listItem.Update();

        listItem = list.AddItem(itemCreateInfo);
        listItem["Title"] = "Validate SharePoint interaction.";
        listItem["Category"] = "Test";
        listItem["Estimate"] = "18";
        listItem.Update();

        listItem = list.AddItem(itemCreateInfo);
        listItem["Title"] = "Develop user interface.";
        listItem["Category"] = "Development";
        listItem["Estimate"] = "18";
        listItem.Update();

        clientContext.ExecuteQuery();
    }
}

In vielen Situationen, in denen Sie ein Clientobjekt erstellen können, kann die Anwendung eine Add-Methode aufrufen, die ein Objekt, das Erstellungsinformationen angibt, als Argument hat. Dieses Beispiel veranschaulicht, wie Sie mithilfe der ListCreationInformation-Klasse ein List-Objekt und mithilfe der ListItemCreationInformation-Klasse ein ListItem-Objekt erstellen können. Eigenschaften der Klasse für die Erstellungsinformationen legen Sie häufig nach dem Instanziieren der Klasse fest. Wie Sie sehen, legt der Code die Title- und die TemplateType-Eigenschaft des ListItemCreationInformation-Objekts fest. Beachten Sie Folgendes: Zum Erstellen einer Liste rufen Sie die Add()-Methode auf, zum Erstellen eines ListItem-Objekts jedoch die AddItem()-Methode. Die Add()-Methode erstellt eine Liste in der Auflistung, während die AddItem()-Methode ein einzelnes Listenelement erstellt.

Beim Erstellen von Feldern in einer Liste wird ebenfalls keine Add-Methode verwendet. Der Grund: Wenn Sie Felder erstellen, legen Sie nicht wirklich eine Instanz der Field-Klasse an. Sie erstellen eine Instanz einer Klasse, die sich von der Field-Klasse ableitet. Für diese abgeleiteten Klassen gibt es zahlreiche Optionen, und der Einsatz einer Add-Methode würde das Design einer FieldCreationInformation-Klasse deutlich verkomplizieren. Aus diesem Grund enthält das Clientobjektmodell keine solche Klasse. Die einfachste Methode zum Erstellen eines Felds besteht vielmehr darin, XML-Code zu schreiben, der das Feld definiert, und diesen dann an die AddFieldAsXml()-Methode zu übergeben. Es gibt eine Add()-Methode, die Sie zum Erstellen eines Felds verwenden können. Anstelle eines FieldCreationInformation-Objekts erfordert diese jedoch ein weiteres Field-Objekt als Parameter, den sie als Prototyp für das zu erstellende Feld verwendet. Dies ist in bestimmten Situationen sinnvoll.

TippTipp

Im Abschnitt Ermitteln des Schemas für Felder dieses Artikels wird eine einfache Methode zum Ermitteln des XML-Codes beschrieben, den Sie für zu erstellende Felder angeben müssen.

Beachten Sie, dass der SharePoint-Datenbank natürlich erst dann tatsächlich Objekte hinzugefügt werden, wenn die Anwendung die ExecuteQuery()-Methode aufruft.

Ein weiterer Punkt ist in diesem Beispiel zu bedenken: Nach dem Aufruf der AddItem()-Methode werden in dem Beispiel drei indizierte Eigenschaften festgelegt. Der Code legt die Werte der Felder fest, die der Liste zuvor hinzugefügt wurden. Nach dem Festlegen dieser Eigenschaften muss die Anwendung die Update()-Methode aufrufen. Damit wird dem Clientobjektmodell mitgeteilt, dass diese Objekte geändert wurden. Geschieht dies nicht, funktioniert das Clientobjektmodell nicht fehlerfrei. Die Update()-Methode finden Sie auch in einigen Beispielen weiter unten, in denen ich zeige, wie Sie vorhandene Clientobjekte ändern können.

Da uns nun einige Daten vorliegen, wollen wir uns ein paar interessante Möglichkeiten ansehen, um Abfragen in diesen Daten auszuführen und die Daten zu ändern.

Verwenden von Collaborative Application Markup Language (CAML) zum Durchführen von Abfragen in Listen

Das folgende Beispiel zeigt, wie Sie mithilfe von CAML Abfragen in der Liste ausführen können, die Sie im vorherigen Beispiel erstellt haben. Dieses Beispiel gibt die Development -Elemente aus unserer Testliste aus.

using System;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main(string[] args)
    {
        ClientContext clientContext = new ClientContext("http://intranet.contoso.com");
        List list = clientContext.Web.Lists.GetByTitle("Client API Test List");
        CamlQuery camlQuery = new CamlQuery();
        camlQuery.ViewXml =
            @"<View>
                <Query>
                  <Where>
                    <Eq>
                      <FieldRef Name='Category'/>
                      <Value Type='Text'>Development</Value>
                    </Eq>
                  </Where>
                </Query>
                <RowLimit>100</RowLimit>
              </View>";
        ListItemCollection listItems = list.GetItems(camlQuery);
        clientContext.Load(
             listItems,
             items => items
                 .Include(
                     item => item["Title"],
                     item => item["Category"],
                     item => item["Estimate"]));
        clientContext.ExecuteQuery();
        foreach (ListItem listItem in listItems)
        {
            Console.WriteLine("Title: {0}", listItem["Title"]);
            Console.WriteLine("Category: {0}", listItem["Category"]);
            Console.WriteLine("Estimate: {0}", listItem["Estimate"]);
            Console.WriteLine();
        }
    }
}

Dieses Beispiel generiert die folgende Ausgabe.

Title: Develop proof-of-concept.
Category: Development
Estimate: 42

Title: Develop user interface.
Category: Development
Estimate: 18

Vielleicht erkennen Sie einen Unterschied zwischen den Lambda-Ausdrücken, die Sie in diesem Beispiel angeben, und den Lambda-Ausdrücken im Beispiel im Abschnitt Einschränken von Resultsets. Sie müssen die Include()-Erweiterungsmethode verwenden, um die Eigenschaften anzugeben, die Sie für jedes Element in der zu ladenden Auflistung laden möchten. Der items-Parameter des Lambda-Ausdrucks hat den Typ ListItemCollection. Dieser enthält natürlich keine indizierte Eigenschaft, mit der wir angeben könnten, welche Eigenschaften für die Elemente in der Auflistung geladen werden sollen. Stattdessen rufen Sie die Include()-Erweiterungsmethode auf, mit der Sie angeben können, welche Parameter dieser untergeordneten Auflistung geladen werden sollen. Parameter für Lambda-Ausdrücke in der Include()-Erweiterungsmethode weisen den Typ auf, den auch die Elemente der Auflistung haben. Daher können Sie die für jedes Element in der Auflistung zu ladenden Eigenschaften angeben.

Wie schon erwähnt, ist es nicht unbedingt notwendig, die genaue Semantik dieser Verwendung von Lambda-Ausdrücken zu verstehen. Merken Sie sich einfach die zwei folgenden Codierungsidiome:

Wenn Sie anfordern, dass das Clientobjektmodell bestimmte Eigenschaften eines Clientobjekts lädt (und nicht einer Auflistung von Clientobjekten), dann geben Sie die Eigenschaften in dem Lambda-Ausdruck an, den Sie direkt in der Load()-Methode hinzufügen.

clientContext.Load(site,
    s => s.Title,
    s => s.Description);

Wenn Sie anfordern, dass das Clientobjektmodell bestimmte Eigenschaften jedes Elements in einer Auflistung von Clientobjekten lädt, verwenden Sie die Include()-Erweiterungsmethode und übergeben die Lambda-Ausdrücke, die die gewünschten Eigenschaften angeben, an die Include()-Methode.

clientContext.Load(
    listItems,
    items => items.Include(
        item => item["Title"],
        item => item["Category"],
        item => item["Estimate"]));

Filtern der untergeordneten Auflistung, die von der "Load"-Methode zurückgegeben wird, mithilfe von "LINQ"

Da die Include()-Erweiterungsmethode IQueryable<T> zurückgibt, können Sie eine Verkettung von der Include()-Methode in die IQueryable<T>.Where-Erweiterungsmethode festlegen. Dies ist eine schnelle Methode zum Filtern des Resultsets. Diese Funktion sollten Sie nur zum Ausführen von Abfragen in Clientobjektauflistungen verwenden, die nicht Auflistungen von ListItem-Objekten sind. Sie könnten dieses Verfahren zwar zum Filtern von Auflistungen von ListItem-Objekten verwenden, doch erzielen Sie eine bessere Leistung, wenn Sie CAML verwenden. Lassen Sie es mich noch einmal betonen:

VorsichtVorsicht

Verwenden Sie niemals die IQueryable<T>.Where-Erweiterungsmethode, wenn Sie Abfragen in ListItem-Objekten ausführen. Der Grund ist, dass das Clientobjektmodell zuerst das Ergebnis der CAML-Abfrage auswertet, dann die Ergebnisse abruft und anschließend die sich ergebende Auflistung mithilfe von LINQ filtert. Wenn Sie eine sehr umfangreiche Liste mit LINQ anstatt mit CAML filtern, versucht das Clientobjektmodell, vor dem Filtern mit LINQ alle Elemente in der Liste abzurufen. Das hat zur Folge, dass entweder Abfragen ausgegeben werden, die zu viele Systemressourcen beanspruchen, oder ein Fehler bei der Abfrage auftritt. Die Ursache hierfür lässt sich nur verstehen, wenn Sie die interne Funktionsweise des Clientobjektmodells kennen. Sie müssen beim Ausführen von Abfragen in Listenelementen CAML verwenden.

Im folgenden Beispiel wird im Clientobjektmodell eine Abfrage nach allen Listen ausgeführt, die nicht verborgen sind. Beachten Sie, dass Sie eine using-Direktive für den System.Linq-Namespace einfügen müssen.

using System;
using System.Linq;
using Microsoft.SharePoint.Client;
 
class Program
{
    static void Main(string[] args)
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        ListCollection listCollection = clientContext.Web.Lists;
        clientContext.Load(
            listCollection,
            lists => lists
                .Include(
                    list => list.Title,
                    list => list.Hidden)
                . Where(list => ! list.Hidden)
             );
        clientContext.ExecuteQuery();
        foreach (var list in listCollection)
            Console.WriteLine(list.Title);
    }
}

Auf meinem Server generiert dieser Beispielcode folgende Ausgabe.

Announcements
Calendar
Client API Test List
Content and Structure Reports
Customized Reports
Eric's ToDo List
Eric's Wiki
Form Templates
Links
Reusable Content
Shared Documents
Site Assets
Site Collection Documents
Site Collection Images
Site Pages
Style Library
Tasks
Team Discussion
Workflow Tasks

Verwenden der "LoadQuery"-Methode

Die LoadQuery()-Methode ähnelt in ihrer Funktionalität der Load()-Methode, abgesehen davon, dass sie dem Clientobjektmodell unter bestimmten Umständen eine effizientere Abfrageverarbeitung und Speichernutzung ermöglicht. Sie erlaubt zudem einen flexibleren Programmierstil.

Die LoadQuery()-Methode hat eine andere Semantik als die Load()-Methode. Während die Load()-Methode das Clientobjekt (oder die Auflistung von Clientobjekten) mit Daten vom Server auffüllt, füllt die LoadQuery()-Methode eine neue Auflistung auf und gibt sie zurück. Das bedeutet, dass Sie mehrmals eine Abfrage in der gleichen Objektauflistung ausführen und für jede Abfrage ein eigenes Resultset aufbewahren können. Beispielsweise können Sie eine Abfrage nach allen Elementen in einer Projektliste ausführen, die einer bestimmten Person zugewiesen sind, und eine separate Abfrage nach allen Elementen ausführen, bei denen die geschätzte Stundenzahl einen bestimmten Schwellenwert überschreitet, und auf beide Resultsets gleichzeitig zugreifen. Diese Methode ermöglicht es Ihnen zudem, diese Auflistungen den gültigen Bereich übersteigen zu lassen, sodass sie für die automatische Speicherbereinigung (Garbage Collection) in Frage kommen. Auflistungen, die Sie mit der Load()-Methode laden, werden nur dann in die automatische Speicherbereinigung einbezogen, wenn die Clientkontextvariable selbst den gültigen Bereich überschreitet. Abgesehen von diesen Unterschieden bietet die LoadQuery()-Methode die gleichen Funktionen wie die Load()-Methode.

Im folgenden Beispiel wird mithilfe der LoadQuery()-Methode eine Liste aller Listen in der Website abgerufen.

using System;
using System.Collections.Generic;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main(string[] args)
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        Web site = clientContext.Web;
        ListCollection lists = site.Lists;
        IEnumerable<List> newListCollection = clientContext.LoadQuery(
            lists.Include(
                list => list.Title,
                list => list.Id,
                list => list.Hidden));
        clientContext.ExecuteQuery();
        foreach (List list in newListCollection)
            Console.WriteLine("Title: {0} Id: {1}",
                list.Title.PadRight(40), list.Id.ToString("D"));
    }
}

Beachten Sie, dass die LoadQuery()-Methode eine neue Listenauflistung zurückgibt, die Sie durchlaufen können. Die neue Listenauflistung hat den Typ IEnumerable<List>, und nicht ListCollection.

Bei der Semantik der LoadQuery()-Methode ist ein Aspekt besonders zu beachten. Im vorherigen Beispiel werden nach der Rückgabe durch die ExecuteQuery()-Methode die Eigenschaftenwerte der ursprünglichen Listenvariablen nicht aufgefüllt. Soll diese Liste aufgefüllt werden, müssen Sie die Load()-Methode explizit aufrufen und angeben, welche Eigenschaften geladen werden sollen.

Steigern der Leistung durch Schachteln von "Include"-Anweisungen in der "LoadQuery"-Methode

Beim Aufrufen der LoadQuery()-Methode können Sie mehrere Ebenen von Eigenschaften angeben, die geladen werden sollen. Dadurch kann das Clientobjektmodell den Zugriff auf den Server, auf dem SharePoint Foundation ausgeführt wird, optimieren, denn es muss weniger Aufrufe an den Server senden, auf dem SharePoint Foundation ausgeführt wird, um die gewünschten Daten abzurufen. Mit der folgenden Abfrage werden alle Listen aus der Website und alle Felder aus jeder Liste abgerufen. Die Ergebnisse werden in der Konsole ausgegeben, wobei jeweils angegeben wird, ob die Liste oder das Feld verborgen ist.

using System;
using System.Collections.Generic;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main()
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        IEnumerable<List> lists = clientContext.LoadQuery(
            clientContext.Web.Lists.Include(
                list => list.Title,
                list => list.Hidden,
                list => list.Fields.Include(
                    field => field.Title,
                    field => field.Hidden)));
        clientContext.ExecuteQuery();
        foreach (List list in lists)
        {
            Console.WriteLine("{0}List: {1}",
                list.Hidden ? "Hidden " : "", list.Title);
            foreach (Field field in list.Fields)
                Console.WriteLine("  {0}Field: {1}",
                    field.Hidden ? "Hidden " : "",
                    field.Title);
        }
    }
}

Bei dieser Vorgehensweise funktioniert der Serverteil des Clientobjektmodells effizienter, als wenn die Anwendung zuerst eine Liste der Listen und dann die Felder für jede Liste laden würde.

Filtern der untergeordneten Auflistung, die von der "LoadQuery"-Methode zurückgegeben wird, mithilfe von "LINQ"

Die LoadQuery()-Methode verwendet ein Objekt vom Typ IQueryable<T> als Parameter. Das gibt Ihnen die Möglichkeit, anstelle von CAML LINQ-Abfragen zu schreiben, um die Ergebnisse zu filtern. In diesem Beispiel wird eine Auflistung aller Dokumentbibliotheken zurückgegeben, die nicht verborgen sind.

using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.SharePoint.Client;
 
class Program
{
    static void Main(string[] args)
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        ListCollection listCollection = clientContext.Web.Lists;
        IEnumerable<List> hiddenLists = clientContext.LoadQuery(
            listCollection
                . Where(list => !list.Hidden &&
                      list.BaseType == BaseType.DocumentLibrary));
        clientContext.ExecuteQuery();
        foreach (var list in hiddenLists)
            Console.WriteLine(list.Title);
    }
}

Aktualisieren von Clientobjekten

Das Aktualisieren von Clientobjekten mithilfe des Clientobjektmodells ist relativ einfach. Sie rufen die Objekte ab, ändern Eigenschaften, rufen die Update-Methode für jedes Objekt auf, das Sie ändern, und rufen dann die ExecuteQuery()-Methode auf. Im folgenden Beispiel werden Elemente in der Client-API-Testlistedahin gehend geändert, dass die Schätzung für alle Entwicklungselemente um 50 Prozent angehoben wird (ein häufig vorkommender Vorgang).

using System;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main(string[] args)
    {
        ClientContext clientContext = new ClientContext("http://intranet.contoso.com");
        List list = clientContext.Web.Lists.GetByTitle("Client API Test List");
        CamlQuery camlQuery = new CamlQuery();
        camlQuery.ViewXml =
            @"<View>
                <Query>
                  <Where>
                    <Eq>
                      <FieldRef Name='Category'/>
                      <Value Type='Text'>Development</Value>
                    </Eq>
                  </Where>
                </Query>
                <RowLimit>100</RowLimit>
              </View>";
        ListItemCollection listItems = list.GetItems(camlQuery);
        clientContext.Load(
             listItems,
             items => items.Include(
                 item => item["Category"],
                 item => item["Estimate"]));
        clientContext.ExecuteQuery();
        foreach (ListItem listItem in listItems)
        {
            listItem["Estimate"] = (double)listItem["Estimate"] * 1.5;
            listItem.Update();
        }
        clientContext.ExecuteQuery();
    }
}

Löschen von Clientobjekten

Das Löschen von Clientobjekten ist eine ähnlich einfache Aufgabe. Allerdings ist beim Löschen von Clientobjekten aus einer Clientobjektauflistung eine sehr wichtige Dynamik zu beachten. Sie können beim Löschen von Objekten nicht die Auflistung durchlaufen. Sobald Sie das erste Objekt löschen, funktioniert der Iterator der Clientobjektauflistung nicht mehr korrekt. Der Iterator löst möglicherweise eine Ausnahme aus, oder er wird ohne weitere Meldung beendet, ohne jedoch alle Elemente in der Auflistung durchgegangen zu sein. Sie müssen die Auflistung stattdessen mithilfe der ToList-Methode in ein List<T> materialisieren und dann diese Liste durchlaufen, wobei alle Clientobjekte gelöscht werden.

Im folgenden Beispiel werden die Testelemente aus der Client-API-Testlistegelöscht. Es veranschaulicht die Verwendung der ToList-Methode zum Materialisieren der Auflistung, bevor Sie diese durchlaufen:

using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main(string[] args)
    {
        ClientContext clientContext = new ClientContext("http://intranet.contoso.com");
        List list = clientContext.Web.Lists.GetByTitle("Client API Test List");
        CamlQuery camlQuery = new CamlQuery();
        camlQuery.ViewXml =
            @"<View>
                <Query>
                  <Where>
                    <Eq>
                      <FieldRef Name='Category'/>
                      <Value Type='Text'>Test</Value>
                    </Eq>
                  </Where>
                </Query>
                <RowLimit>100</RowLimit>
              </View>";
        ListItemCollection listItems = list.GetItems(camlQuery);
        clientContext.Load(
             listItems,
             items => items.Include(
                 item => item["Title"]));
        clientContext.ExecuteQuery();
        foreach (ListItem listItem in listItems.ToList())
            listItem.DeleteObject();
        clientContext.ExecuteQuery();
    }
}

Im folgenden Codebeispiel wird die falsche Vorgehensweise gezeigt.

clientContext.Load(
    listItems,
    items => items.Include(
        item => item["Title"]));
clientContext.ExecuteQuery();

// The ToList() method call is removed in the following line.
foreach (ListItem listItem in listItems)  
    listItem.DeleteObject();

clientContext.ExecuteQuery();

Zum Bereinigen der Client-API-Testliste finden Sie hier einen Beispielcode, mit dem die Listen und deren Elemente gelöscht werden.

using System;
using Microsoft.SharePoint.Client;

class DisplayWebTitle
{
    static void Main()
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        clientContext.Web.Lists.GetByTitle("Client API Test List")
            .DeleteObject();
        clientContext.ExecuteQuery();
    }
}

Ermitteln des Schemas für Felder

Wie versprochen, erfahren Sie in diesem Abschnitt, wie Sie auf einfache Weise das XML-Schema ermitteln können, das Sie zum Anlegen der in einer Liste zu erstellenden Felder verwenden. Zuerst erstellen Sie auf der SharePoint-Website eine Liste mit Spalten, die gemäß Ihren Vorstellungen konfiguriert sind. Anschließend können Sie den folgenden Beispielcode verwenden, um den XML-Code auszugeben, der diese Felder erstellt.

Im folgenden Beispiel werden die Feldschemas für die Felder ausgegeben, die ich der Client-API-Testliste hinzugefügt hatte.

using System;
using System.Linq;
using System.Xml.Linq;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main(string[] args)
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        List list = clientContext.Web.Lists
            .GetByTitle("Client API Test List");
        clientContext.Load(list);
        FieldCollection fields = list.Fields;
        clientContext.Load(fields);
        clientContext.ExecuteQuery();
        foreach (var f in fields)
        {
            XElement e = XElement.Parse(f.SchemaXml);
            string name = (string)e.Attribute("Name");
            if (name == "Category" || name == "Estimate")
            {
                e.Attributes("ID").Remove();
                e.Attributes("SourceID").Remove();
                e.Attributes("ColName").Remove();
                e.Attributes("RowOrdinal").Remove();
                e.Attributes("StaticName").Remove();
                Console.WriteLine(e);
                Console.WriteLine("===============");
            }
        }
    }
}

Wenn Sie diesen Code ausführen, nachdem Sie die Liste anhand des Beispielprogramms im Abschnitt Erstellen und Auffüllen von Listen erstellt haben, generiert er die folgende Ausgabe.

<Field Type="Choice" DisplayName="Category" Format="Dropdown" Name="Category">
  <Default>Specification</Default>
  <CHOICES>
    <CHOICE>Specification</CHOICE>
    <CHOICE>Development</CHOICE>
    <CHOICE>Test</CHOICE>
    <CHOICE>Documentation</CHOICE>
  </CHOICES>
</Field>
===============
<Field Type="Number" DisplayName="Estimate" Name="Estimate" />
===============

Mit diesem Beispielcode werden Attribute entfernt, die zum Erstellen des Felds nicht benötigt werden.

Zugreifen auf umfangreiche Listen

Gemäß den Entwicklungsrichtlinien für SharePoint sollten Sie nicht versuchen, mehr als 2.000 Elemente in einer einzigen Abfrage abzurufen. Falls dies in Ihrer Anwendung jedoch möglich ist, empfiehlt es sich, das RowLimit-Element in den CAML-Abfragen zu verwenden, um die vom Clientobjektmodell für Ihre Anwendung abgerufene Datenmenge zu begrenzen. Manchmal ist es erforderlich, auf alle Elemente in einer Liste zuzugreifen, die möglicherweise mehr als 2.000 Elemente enthält. In diesem Fall besteht das bewährte Verfahren darin, die Elemente in Blöcken von 2.000 durchzublättern. In diesem Abschnitt wird eine Möglichkeit für das Durchblättern mithilfe der ListItemCollectionPosition-Eigenschaft erklärt.

using System;
using System.Linq;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main()
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");

        List list = clientContext.Web.Lists
            .GetByTitle("Client API Test List");

        // First, add 20 items to Client API Test List so that there are
        // enough records to show paging.
        ListItemCreationInformation itemCreateInfo =
            new ListItemCreationInformation();
        for (int i = 0; i < 20; i++)
        {
            ListItem listItem = list.AddItem(itemCreateInfo);
            listItem["Title"] = String.Format("New Item #{0}", i);
            listItem["Category"] = "Development";
            listItem["Estimate"] = i;
            listItem.Update();
        }
        clientContext.ExecuteQuery();

        // This example shows paging through the list ten items at a time.
        // In a real-world scenario, you would want to limit a page to
        // 2000 items.
        ListItemCollectionPosition itemPosition = null;
        while (true)
        {
            CamlQuery camlQuery = new CamlQuery();
            camlQuery.ListItemCollectionPosition = itemPosition;
            camlQuery.ViewXml =
                @"<View>
                    <ViewFields>
                      <FieldRef Name='Title'/>
                      <FieldRef Name='Category'/>
                      <FieldRef Name='Estimate'/>
                    </ViewFields>
                    <RowLimit>10</RowLimit>
                  </View>";
            ListItemCollection listItems = list.GetItems(camlQuery);
            clientContext.Load(listItems);
            clientContext.ExecuteQuery();
            itemPosition = listItems.ListItemCollectionPosition;
            foreach (ListItem listItem in listItems)
                Console.WriteLine("  Item Title: {0}", listItem["Title"]);
            if (itemPosition == null)
                break;
            Console.WriteLine(itemPosition.PagingInfo);
            Console.WriteLine();
        }
    }
}

Dieses Beispiel generiert die folgende Ausgabe:

  Item Title: Write specs for user interface.
  Item Title: Develop proof-of-concept.
  Item Title: Write test plan for user interface.
  Item Title: Validate SharePoint interaction.
  Item Title: Develop user interface.
  Item Title: New Item #0
  Item Title: New Item #1
  Item Title: New Item #2
  Item Title: New Item #3
  Item Title: New Item #4
Paged=TRUE&p_ID=10

  Item Title: New Item #5
  Item Title: New Item #6
  Item Title: New Item #7
  Item Title: New Item #8
  Item Title: New Item #9
  Item Title: New Item #10
  Item Title: New Item #11
  Item Title: New Item #12
  Item Title: New Item #13
  Item Title: New Item #14
Paged=TRUE&p_ID=20

  Item Title: New Item #15
  Item Title: New Item #16
  Item Title: New Item #17
  Item Title: New Item #18
  Item Title: New Item #19

Asynchrone Verarbeitung

Wenn Sie eine Anwendung erstellen, die an SharePoint-Websites angehängt werden muss, die möglicherweise nicht verfügbar sind, oder wenn Sie regelmäßig Abfragen aufrufen müssen, die vielleicht viel Zeit in Anspruch nehmen, sollten Sie asynchrone Verarbeitung in Erwägung ziehen. Dadurch reagiert die Anwendung weiterhin auf Eingaben des Benutzers, während die Abfrage in einem separaten Thread ausgeführt wird. Im Hauptthread können Sie einen Zeitgeber definieren, der ggf. meldet, wenn die Abfrage länger dauert als die festgelegte Höchstdauer. Sie können den Benutzer über den Status der Abfrage auf dem Laufenden halten, und wenn die Abfrage abgeschlossen ist, können die Ergebnisse angezeigt werden.

In der JavaScript-Version des Clientobjektmodells und in der Silverlight-Version (wenn die Benutzeroberfläche modifiziert wird) wird asynchrone Verarbeitung verwendet. Im Thema Data Retrieval Overview im SharePoint 2010 SDK finden Sie Beispiele zur Verwendung der asynchronen Verarbeitung mit JavaScript und Silverlight.

Beim Erstellen einer traditionellen Anwendung, die auf .NET Framework basiert, z. B. einer Windows Forms- oder einer WPF-Anwendung, empfiehlt sich die Verwendung der asynchronen Verarbeitung. Im folgenden Beispiel wird mithilfe der BeginInvoke-Methode eine Abfrage asynchron ausgeführt. Beachten Sie, dass der Code einen Anweisungs-Lambda-Ausdruck an die BeginInvoke-Methode übergibt. Daher ist die Erstellung dieses Musters eine bequeme Lösung, denn der Anweisungs-Lambda-Ausdruck kann in der Methode, in der er enthalten ist, auf automatische Variablen verweisen. Wie Sie sehen, hat der Anweisungs-Lambda-Ausdruck Zugriff auf die clientContext - und die newListCollection -Variable. Mithilfe von Microsoft Visual C#-Abschlüssen funktioniert der Code wie erwartet.

using System;
using System.Collections.Generic;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main(string[] args)
    {
        AsynchronousAccess asynchronousAccess = new AsynchronousAccess();
        asynchronousAccess.Run();
        Console.WriteLine("Before exiting Main");
        Console.WriteLine();
        Console.WriteLine("In a real application, the application can");
        Console.WriteLine("continue to be responsive to the user.");
        Console.WriteLine();
        Console.ReadKey();
    }
}

class AsynchronousAccess
{
    delegate void AsynchronousDelegate();

    public void Run()
    {
        Console.WriteLine("About to start a query that will take a long time.");
        Console.WriteLine();
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        ListCollection lists = clientContext.Web.Lists;
        IEnumerable<List> newListCollection = clientContext.LoadQuery(
            lists.Include(
                list => list.Title));
        AsynchronousDelegate executeQueryAsynchronously =
            new AsynchronousDelegate(clientContext.ExecuteQuery);
        executeQueryAsynchronously.BeginInvoke(
            arg =>
            {
                clientContext.ExecuteQuery();
                Console.WriteLine("Long running query completed.");
                foreach (List list in newListCollection)
                    Console.WriteLine("Title: {0}", list.Title);
            }, null);
    }
}

Das Beispiel generiert die folgende Ausgabe.

About to start a query that will take a long time.

Before exiting Main

In a real application, the application can
continue to be responsive to the user.

Long running query completed.
Title: Announcements
Title: Cache Profiles
Title: Calendar
Title: Client API Test List
Title: Content and Structure Reports
Title: Content type publishing error log
Title: Converted Forms
Title: Customized Reports
Title: Eric's ToDo List
Title: Eric's Wiki
Title: Form Templates
Title: Links

Weitere Ressourcen

Weitere Informationen finden Sie in den folgenden Ressourcen: