SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルの使用

概要 :  SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルを使用して .NET Framework をベースとしたアプリケーションを作成し、SharePoint Foundation 2010 が実行されるサーバー上にコードをインストールせずにクライアントから SharePoint のコンテンツにアクセスする方法を説明します。

最終更新日: 2015年3月9日

適用対象: Business Connectivity Services | Office 2010 | Open XML | SharePoint Designer 2010 | SharePoint Foundation 2010 | SharePoint Online | SharePoint Server 2010 | Visual Studio

この記事の内容
概要
SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルの使用
クライアント オブジェクト モデルの動作
Windows コンソールのマネージ クライアント オブジェクト モデル アプリケーションの作成
SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルの概要
オブジェクト ID の使用
結果セットのトリミング
リストの作成と入力
リストにクエリを実行するための CAML の使用
LINQ を使用する Load によって返される子コレクションのフィルター処理
LoadQuery メソッドの使用
LoadQuery での入れ子の Include ステートメントによるパフォーマンスの向上
LINQ を使用する LoadQuery によって返される子コレクションのフィルター処理
クライアント オブジェクトの更新
クライアント オブジェクトの削除
フィールドのスキーマの取得
大きなリストへのアクセス
非同期処理
参考資料

提供元:  Eric White、Microsoft Corporation

目次

  • 概要

  • SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルの使用

  • クライアント オブジェクト モデルの動作

  • Windows コンソールのマネージ クライアント オブジェクト モデル アプリケーションの作成

  • SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルの概要

  • オブジェクト ID の使用

  • 結果セットのトリミング

  • リストの作成と入力

  • リストにクエリを実行するための CAML の使用

  • LINQ を使用する Load によって返される子コレクションのフィルター処理

  • LoadQuery メソッドの使用

  • LoadQuery での入れ子の Include ステートメントによるパフォーマンスの向上

  • LINQ を使用する LoadQuery によって返される子コレクションのフィルター処理

  • クライアント オブジェクトの更新

  • クライアント オブジェクトの削除

  • フィールドのスキーマの取得

  • 大きなリストへのアクセス

  • 非同期処理

  • 参考資料

概要

SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルを使用すると、Microsoft SharePoint Foundation 2010 が実行されているサーバーにコードをインストールせずに SharePoint のコンテンツにアクセスするクライアント アプリケーションを設計できます。たとえば、Microsoft .NET Framework をベースとしたアプリケーション、機能の豊富な対話型の Web パーツ、Microsoft Silverlight アプリケーション、および SharePoint Web パーツのクライアント側で実行される ECMAScript (JavaScript、JScript) アプリケーションの作成を含むアプリケーションの新しいカテゴリを構築できます。以下に例を示します。

  • チーム リーダーが、チームの仕事の管理に必要な多数のリストを含む SharePoint サイトを作成します。そのリーダーは、状況に応じてこれらのリストを変更する必要があります (Open XML のスプレッドシートが使用されている割り当て表や見積書の更新、別の SharePoint リストへの項目の移動など)。このリーダーは、管理に役立つ簡単なカスタム アプリケーションを作成することを考えています。

  • 従来のリッチ クライアントのアプリケーションを販売しているソフトウェア会社は、SharePoint のドキュメント ライブラリとリストを、その会社のアプリケーションに統合することを計画し、この統合がシームレスになるように、さらにはユーザーから見えないようにすることを考えています。

  • SharePoint の開発者は、リストのコンテンツをカスタムの AJAX Web コードで利用する SharePoint 展開用の機能の豊富な Web パーツを作成することを考えています。また、同じ働きをする、機能がさらに豊富な Silverlight アプリケーションを作成することも考えています。

こういった人々に共通していることは何でしょうか? それは、これらの人々が、SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルを使用して目的を達成できることです。SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルを使用すると、SharePoint サイトのすべての一般的なオブジェクトを利用する、クライアント側のコードを書くことができます。オブジェクト モデルを利用すると、リストの追加および削除、リスト アイテムの追加、更新、および削除、ドキュメント ライブラリのドキュメントの変更、サイトの作成、アイテムの権限の管理、およびページへの Web パーツの追加と削除を行うことができます。

以前は、オプションがほとんどありませんでした。SharePoint のリストおよび他の機能とのやりとりに Web サービスを使用できましたが、これは難易度の高い作業でした。Web サービスで必要な機能が実現されない場合は、サーバー側のコードを書いて新しい Web サービスを提供することができました (さらに難易度の高い作業です)。一部の IT 部門では、サーバー側のコードを許可していなかったり、IT 部門が書いたコードのみを許可している場合があり、オプションとしてサーバー側のコードを使用できない場合もありました。SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルを使用すると、新しい種類のアプリケーションが可能になり、SharePoint のコンテンツとのやりとりを行うクライアント側のコードが書きやすくなります。

SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルの使用

SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデル (クライアント オブジェクト モデル) を使用するには、SharePoint Foundation が実行されているサーバー上で使用されるオブジェクト モデルに似た API を使用する .NET Framework をベースとしたマネージ コードを書きます。クライアント オブジェクト モデルには、サイト コレクションの情報、サイトの情報、および、リストとリスト項目の情報にアクセスするためのクラスがあります。

Web パーツの場合は, .NET Framework API に似た ECMAScript (JavaScript、JScript) のプログラミング インターフェイスを使用します。Silverlight の場合は、クライアント上の .NET Framework をとおして利用できる API のサブセットを使用します。この記事で説明されている情報の多くは JavaScript と Silverlight API に関連していますが、この記事では、主に, .NET Framework をベースとしたクライアント アプリケーションから SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルを使用する方法を中心に説明しています。

SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルは、5 つの名前空間を含む 2 つのアセンブリで構成されています。それらの名前空間には、多数の利用可能なクラスがあります。それらのクラスの多くはオブジェクト モデルによって内部的に使用されます。そのため、関係するのは、それらのサブセットの、主に、SharePoint Foundation のサーバー オブジェクト モデルの一部のなじみのあるクラスに直接対応するクラスのみです。

表 1. クライアント側のクラスとサーバー側の対応するクラス

クライアント

サーバー

ClientContext

SPContext

Site

SPSite

Web

SPWeb

List

SPList

ListItem

SPListItem

Field

SPField

SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルでは、サーバー オブジェクト モデルと同じ従来の命名パターンがサイト コレクションとサイトに使用されることに注意してください。Site クラスはサイト コレクションを表し、Web クラスはサイトを表します。これらのクラスを使用するための個人設定は、変数名によってサイト コレクションまたはサイトのどちらかを表すように、変数に名前を付けるためのものです。ただし、SiteWeb クラスを使用して、それらを宣言する必要があります。

次の例で、変数に名前を付ける方法を示します。

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

クライアント オブジェクト モデルの動作

SharePoint のコンテンツを使用するアプリケーションは、メソッドの呼び出しと戻り値の取得、Collaborative Application Markup Language (CAML) クエリの送信と結果の取得、プロパティの設定、取得など、いくつかの方法で API を使用してやりとりを行います。API を使用して特定のタスクを実行すると、SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルによって、こういった API の使用が XML にバンドルされ、SharePoint Foundation が実行されているサーバーに送信されます。サーバーでこの要求が受信されると、サーバーのオブジェクト モデルに適切な呼び出しが行われます。応答が収集され、JavaScript Object Notation (JSON) の形式にされて、その JSON が SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルに返されます。クライアント オブジェクト モデルでは、JSON の解析が行われて、結果が .NET Framework オブジェクト (または JavaScript 用の JavaScript オブジェクト) としてアプリケーションに伝えられます。次の図で、これらのやりとりを示します。

図 1. SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデル

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

SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルによってサーバーに XML の送信が開始され、サーバーから JSON が返されるタイミングを制御することを認識することが重要です。

サーバーへの 1 回の呼び出しへの複数のメソッドの呼び出しのバンドルは、ネットワークの実際の速度、ネットワークの待機時間、および要求されるパフォーマンス特性の影響を受けます。SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルによって、すべてのメソッドの呼び出しでサーバーとのやりとりが行われると、システムのパフォーマンスとネットワーク トラフィックの増加によってシステムが動作しなくなる場合があります。

前述したとおり、SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルによってメソッドの呼び出しがバンドルされ、サーバーに要求が送信されるタイミングを明示的に制御します。この処理の一環として、サーバーとのやりとりが開始される前に、サーバーから取得するコンテンツを明示的に指定する必要があります。これが、SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルと SharePoint Foundation 2010 オブジェクト モデルとの間の最も大きな違いです。しかし、このモデルを理解すれば、複雑ではありません。その違いを理解するための最も簡単な方法は、単純なアプリケーションを理解することです。

Windows コンソールのマネージ クライアント オブジェクト モデル アプリケーションの作成

注意

サンプル コード用に Windows のコンソール アプリケーションを使用しますが、他のアプリケーションの形式でも同じ方法を使用できます。

アプリケーションを作成するには、Microsoft.SharePoint.Client.dll および Microsoft.SharePoint.Client.Runtime.dll の 2 つのアセンブリへの参照を追加する必要があります。SharePoint Foundation のインストールで、これらのアセンブリがサーバーにインストールされます。この 2 つのアセンブリは、次のディレクトリに保存されます。

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

重要なメモ重要

SharePoint Foundation のベータ版および Microsoft SharePoint Server 2010 のベータ版を使用する場合は、この 2 つのアセンブリを開発用のクライアント コンピューターの便利な場所にコピーする必要があります。SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルを使用するプロジェクトの設定中に、その場所を指定して、これらのアセンブリへの参照を追加する必要があります。

アプリケーションを作成するには

  1. Microsoft Visual Studio 2010 を起動します。

  2. [ファイル] メニューの [新規作成] をポイントし、[プロジェクト] をクリックします。

  3. [新しいプロジェクト] ダイアログ ボックスの [最近使用したテンプレート] ウィンドウで、[Visual C#] を展開して、[Windows] をクリックします。

  4. [最近使用したテンプレート] ウィンドウの右側で、[コンソール アプリケーション] をクリックします。

  5. 既定では、Visual Studio によって, .NET Framework 4 を対象とするプロジェクトが作成されますが, .NET Framework 3.5 を対象とする必要があります。[ファイルを開く] ダイアログ ボックスの上部にあるリストから、[.NET Framework 3.5] を選択します。

  6. [プロジェクト名] ボックスに、プロジェクトに使用する名前 (FirstClientApiApplication など) を入力します。

  7. [場所] ボックスに、プロジェクトを保存する場所を入力します。

    図 2. [新しいプロジェクト] ダイアログ ボックスでのソリューションの作成

    6fff7a0d-bf31-4042-acb2-72a16fce6e19

  8. [OK] をクリックして、ソリューションを作成します。

Microsoft.SharePoint.Client アセンブリおよび Microsoft.SharePoint.Client.Runtime アセンブリへの参照を追加するには

  1. クライアント オブジェクト モデル アプリケーションで使用するクラスは、 Microsoft.SharePoint.Client.dll および Microsoft.SharePoint.Client.Runtime.dllにあります。前述したとおり、参照を追加する前に、SharePoint Foundation が実行されているサーバーから、クライアントの開発用コンピューターへこれらのアセンブリをコピーしておく必要があります。

  2. [プロジェクト] メニューで、[参照の追加] をクリックして、[参照の追加] ダイアログ ボックスを開きます。

  3. [参照] タブを選択して、 Microsoft.SharePoint.Client.dll および Microsoft.SharePoint.Client.Runtime.dllを保存した場所に移動します。図 3 に示されているように、両方の DLL を選択して [OK] をクリックします。

    図 3. アセンブリへの参照の追加

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

サンプル コードをソリューションに追加するには

  1. Visual Studio で、 Program.cs ソース ファイルの内容を次のコードで置き換えます。

    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. ClientContext(String) コンストラクター内の URL を SharePoint サイトへの URL で置き換えます。ソリューションを作成して実行します。この例では、サイトのタイトルが出力されます。

SharePoint Foundation のサーバー オブジェクト モデルの場合と同様に、アクセスする SharePoint サイト用のコンテキストを作成します。そうすると、コンテキストからサイトへの参照を取得できます。

ExecuteQuery() メソッドの呼び出しによって、SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルからサーバーへ要求が送信されます。アプリケーションによって ExecuteQuery() メソッドが呼び出されるまで、ネットワーク トラフィックはありません。

この例についての重要な点は、Load() メソッドの呼び出しでは、実際には何も読み込まれないことです。その代わりに、アプリケーションによって ExecuteQuery() メソッドが呼び出されるときに siteCollection オブジェクトのプロパティの値を読み込むことを、クライアント オブジェクト モデルに通知します。

以下は、サーバーとのすべてのやりとりのモデルです。

  1. SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルに、行う操作を通知します。これには、オブジェクト (たとえば、List クラス、ListItem クラス、および Web クラスのオブジェクト) のプロパティの値、実行する CAML クエリ、および、挿入、更新または削除を行う ListItem オブジェクトなどのオブジェクトへのアクセスが含まれます。

  2. その後で、ExecuteQuery() メソッドを呼び出します。ExecuteQuery() メソッドを呼び出すまでネットワーク トラフィックは発生しません。その時点まで、アプリケーションは要求の登録のみを行っています。

この例からわかるように、最も単純な場合では、まずクエリを設定して、そのクエリを実行します。これによって、クライアント オブジェクト モデルからサーバーにトラフィックが送信され、そのサーバーからの応答が受信されます。この次のセクションでは、モデルを詳細に見直して、このように設計されている理由や、最終的には、このモデルを使用してアプリケーションを作成する方法を説明します。

SharePoint Foundation 2010 のマネージ クライアント オブジェクト モデルの概要

クライアント オブジェクト モデルの次の点を確認する必要があります。

  • ネットワーク トラフィックを最小限にするためにクライアント オブジェクト モデルで採用されている方法

  • クエリの構造

  • サーバーのパフォーマンスを向上させるテクニック

  • クライアント オブジェクトの作成、更新、および削除を行う方法

  • 非常に大きいリストを扱う方法

こういった件の詳細に入る前に、オブジェクト ID の問題を確認します。

オブジェクト ID の使用

オブジェクト ID に関しての鍵となる考えは、クライアント オブジェクトによって、SharePoint Foundation のサーバー オブジェクト モデルの対応するオブジェクトが、ExecuteQuery() メソッドを呼び出す前と後の両方に参照されることです。ExecuteQuery() メソッドの複数の呼び出しの間、その同じオブジェクトが参照し続けられます。

これは、クエリの設定時に、ExecuteQuery() メソッドを呼び出す前にクエリの詳細な設定を行うために使用できるオブジェクトが、クライアント オブジェクト モデルによって返されることを意味します。これによって、サーバーとの間のトラフィックが発生する前に、より複雑なクエリを記述することができます。より興味深いことが 1 回のクエリで可能で、ネットワーク トラフィックを解消できます。

次の例では、 Announcements リスト オブジェクトを取得し、考えられる最も単純な CAML クエリを使用して、そのリストのすべての項目を取得します。

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"]);
    }
}

この例での一連の動きを説明します。

  1. まず、このコードで、GetByTitle() メソッドが使用されて List オブジェクトが取得されます。この List オブジェクトにはデータが含まれていないことに注意してください。アプリケーションによって ExecuteQuery() メソッドが呼び出されるまでは、どのプロパティにもデータは含まれていません。

  2. その後、list オブジェクトにデータが設定されていなくても、list オブジェクトで GetItems() メソッドが呼び出されます。

  3. 最後に、list オブジェクトと listItems オブジェクトの両方で、Load() メソッドが呼び出されて、その後に ExecuteQuery() メソッドが呼び出されます。

ここでの重要なポイントは、list オブジェクトが、GetByTitle() メソッドが使用されてアプリケーションで初期化されたもので、list オブジェクトが SharePoint データベースから取得された後に、その同じ list オブジェクト上で、クライアント オブジェクト モデルによって CAML クエリが実行される必要があることがクライアント オブジェクト モデルで記憶されていることです。ClientObject クラスから派生するクラスは、これらの形式を持ちます。

また、前述したように、ExecuteQuery() メソッドを呼び出した後に、追加のクエリを設定するために、クライアント オブジェクトを引き続き使用できます。次の例のコードでは、list オブジェクトが読み込まれ、ExecuteQuery() メソッドが呼び出されます。その後、その list クライアント オブジェクトが使用されて List.GetItems メソッドが呼び出され、ExecuteQuery() メソッドが再度呼び出されます。list オブジェクトは ExecuteQuery() メソッドの呼び出しの間、ID を保持しています。

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"]);
    }
}

一部のプロパティとメソッドは、ClientObject クラスから派生していないオブジェクトまたは値の型を返します。クライアント オブジェクト ID を使用してメソッドとプロパティにアクセスすることで利点があるのは、それらのメソッドとプロパティがクライアント オブジェクトまたはクライアント オブジェクトのコレクションを返す場合のみです。たとえば、FieldUrlValue クラス、FieldLookupValue クラスなどの一部のクラスは、ClientValueObject クラスから派生し、ExecuteQuery() メソッドの呼び出しの後まで、それらの型を返すプロパティを使用できません。一部のプロパティは、文字列、整数などの .NET Framework の型を返し、ExecuteQuery() メソッドの呼び出しの後まで、それらを返すプロパティやメソッドも使用できません。それらの値が ExecuteQuery() の呼び出しに設定されるまでプロパティの値は使用できないので、たとえば、リスト内の項目を検索したり、追加のクエリで項目を選択するために、その項目のフィールドの 1 つの値を使用したりすることはできません。ExecuteQuery() メソッドで設定される前にプロパティを使用しようとすると、クライアント オブジェクト モデルによって、PropertyOrFieldNotInitializedException 例外がスローされます。

注意に関するメモ注意

クライアント オブジェクト ID は、1 つの ClientContext オブジェクトにのみ有効です。別の ClientContext オブジェクトを同じ SharePoint サイトに対して初期化する場合は、あるクライアント コンテキストから他のクライアント コンテキストと同時にクライアント オブジェクトを使用できません。

この記事で後述する多数の例では、オブジェクト ID の動作を使用します。

注意

この例では、エラー処理は行われません。 Announcements リストが存在しない場合は、クライアント オブジェクト モデルによって、ExecuteQuery() メソッドの呼び出しで例外がスローされます。存在しないオブジェクトを要求すると失敗する可能性があるコードを書く場合は、例外をキャッチするようにしておく必要があります。

結果セットのトリミング

SharePoint Foundation は、多くの場合、何千人ものユーザーがいる組織に導入されます。ネットワーク経由で SharePoint Foundation にアクセスするアプリケーションを作成する場合は、ネットワーク トラフィックの使用量が最小になるように作成するのは妥当なことです。このためにクライアント オブジェクト モデルが役立つ方法がいくつかあります。最も簡単な方法は、ラムダ式を使用して、クライアント オブジェクト モデルによってアプリケーションに返される必要があるプロパティを厳密に指定することです。

次の例では、クライアント オブジェクト モデルによってサイトのオブジェクトが読み込まれるときに、Title プロパティと Description プロパティのみが読み込まれる必要があることを指定する方法を示します。これによって、サーバーからクライアントに返される JSON の応答のサイズが削減されます。

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

既定では、これらのラムダ式が Load() メソッドの呼び出しに含まれていないと、非常に多数のプロパティ (すべてではありません) が読み込まれます。 最初の 2 つの例では、読み込むプロパティが指定されていない状態で Load() メソッドが呼び出されているので、サーバーが返す JSON のパケットが必要以上に大きくなっています。こういった小さな例ではあまり違いがありませんが、何千ものリスト項目を読み込む場合は、必要なプロパティを注意深く指定することでネットワーク トラフィックが削減されます。

ラムダ式を使用して、Load() メソッドにプロパティのリストを指定できます。クライアント オブジェクト モデルでラムダ式を使用することで派生する利点は、ネットワーク トラフィックの削減以外にもあります。ラムダ式を使用して結果セットのフィルター処理を行う方法を、この記事で後述します。

次に、リストを作成してコンテンツを追加する例を示します。ここで、この記事でこの後に使用するサンプル コンテンツを提供します。

リストの作成と入力

次の例では、リストを作成して、フィールドと項目を追加します。

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

クライアント オブジェクトを作成できる多くの場合、アプリケーションから、作成情報を指定するオブジェクトを引数として利用する Add メソッドを呼び出すことができます。この例では、ListCreationInformation クラスを使用して List オブジェクトを作成する方法と、ListItemCreationInformation クラスを ListItem オブジェクトの作成のために使用する方法を示します。作成情報のクラスのプロパティをインスタンス化の後に設定することがよくあります。このコードでは ListItemCreationInformation オブジェクトの Title プロパティと TemplateType プロパティを設定していることがわかります。リストを作成するには、Add() メソッドを呼び出しますが、ListItem オブジェクトを作成するには、AddItem() メソッドを呼び出すことに注意してください。Add() メソッドによって、コレクションにリストが作成され、AddItem() メソッドによって、1 つのリスト項目が作成されます。

フィールドを作成するときに、実際には Field クラスのインスタンスを作成していないので、リストにフィールドを作成する場合も、Add メソッドは使用されません。ここでは、Field クラスから派生するクラスのインスタンスを作成しています。これらの派生したクラスで使用できるオプションが多数あり、Add メソッドを使用すると、FieldCreationInformation クラスの設計が大幅に複雑化する可能性があります。このため、クライアント オブジェクト モデルには、そのようなクラスは含まれません。その代わりに、フィールドを作成する最も簡単な方法は、フィールドを定義する XML を指定して、その XML を AddFieldAsXml() メソッドに渡す方法です。フィールドの作成に使用できる Add() メソッドがありますが、FieldCreationInformation オブジェクトを利用する代わりに、別の Field オブジェクトを、作成されるフィールドのプロトタイプとして使用するパラメーターとして利用します。この方法は状況によって有用な場合があります。

ヒントヒント

この記事の「フィールドのスキーマの取得」セクションでは、作成するフィールドに指定する必要がある XML を取得する簡単な方法を説明します。

アプリケーションによって ExecuteQuery() メソッドが呼び出されるまで、実際に SharePoint データベースに追加されるオブジェクトはないことに注意してください。

この例では興味深い内容がもう 1 つあります。AddItem() メソッドを呼び出した後に、この例では、3 つのインデックス付きプロパティが設定されていることに注目してください。このコードでは、それまでにリストに追加されたフィールドの値を設定しています。これらのプロパティが設定された後、アプリケーションによって Update() メソッドが呼び出されて、それらのオブジェクトが変更されたことがクライアント オブジェクト モデルに通知される必要があります。そうしないと、クライアント オブジェクト モデルが正しく動作しません。Update() メソッドは、既存のクライアント オブジェクトの変更方法を示す後述する例で使用しています。

これでデータが用意できました。次に、クエリを実行して変更を行う興味深い方法をいくつか説明します。

リストにクエリを実行するための CAML の使用

次の例では、CAML を使用して、1 つ前の例で作成したリストにクエリを実行する方法を示します。この例では、 Development の項目が、テスト用のリストから出力されます。

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

この例では次の出力が生成されます。

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

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

この例で指定するラムダ式と「結果セットのトリミング」のセクションで使用されている例のラムダ式との違いに注目してください。Include() 拡張メソッドを使用して、読み込むコレクションの各アイテムに読み込むプロパティを指定する必要があります。ラムダ式の items パラメーターは、ListItemCollection の型で、そのため、コレクションのアイテムに読み込むプロパティを指定できるようにする、インデックス付きプロパティは含まれません。その代わりに、読み込むその子コレクションのパラメーターを指定できる Include() 拡張メソッドを呼び出します。Include() 拡張メソッドのラムダ式へのパラメーターは、コレクションのアイテムの型です。そのため、コレクションの各アイテムに読み込むプロパティを指定できます。

前述したように、このようなラムダ式の使用方法の正確な形式を完全に理解する必要があるわけではありません。覚える必要があるのは、次の 2 つのコーディングの方法のみです。

クライアント オブジェクト モデルによって (コレクションではなく) クライアント オブジェクトの特定のプロパティが読み込まれるように要求している場合は、Load() メソッドに直接追加するラムダ式でプロパティを指定します。

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

クライアント オブジェクト モデルによってクライアント オブジェクトのコレクションの各アイテムの特定のプロパティが読み込まれるように要求している場合は、Include() 拡張メソッドを使用して、対象のプロパティを指定するラムダ式を Include() メソッドに渡します。

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

LINQ を使用する Load によって返される子コレクションのフィルター処理

Include() 拡張メソッドが IQueryable<T> を返すので、Include() メソッドから IQueryable<T>.Where 拡張メソッドに連結できます。これによって、結果セットのフィルター処理を行う簡潔な方法が実現します。この機能を使用する必要があるのは、ListItem オブジェクトのコレクション以外のクライアント オブジェクトのコレクションにクエリを実行する場合のみです。その理由は、このテクニックを使用して、ListItem オブジェクトのコレクションのフィルター処理を行って、CAML の結果をより良いパフォーマンスで使用できるためです。これは、重要な内容なので繰り返します。

注意に関するメモ注意

ListItem オブジェクトにクエリを実行する場合、IQueryable<T>.Where 拡張メソッドを使用しないでください。その理由は、クライアント オブジェクト モデルによって、まず CAML クエリの結果が評価され、結果が取得されてから、結果のコレクションのフィルター処理が LINQ を使用して行われるためです。CAML の代わりに LINQ を使用して非常に大きなリストのフィルター処理を行う場合は、クライアント オブジェクト モデルによって、LINQ を使用してフィルター処理が行われる前に、リストのすべての項目の取得が行われるので、システム リソースを大量に必要とするクエリが発行されるか、または、クエリが失敗します。これは、クライアント オブジェクト モデルの内部的な動作に基づいて発生します。リストの項目にクエリを実行する場合は、CAML を必ず使用する必要があります。

次の例では、非表示ではないすべてのリストのクライアント オブジェクト モデルにクエリが実行されます。System.Linq 名前空間に対する using ディレクティブを含める必要があることに注意してください。

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

筆者のサーバーでは、この例で次の出力が生成されます。

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

LoadQuery メソッドの使用

LoadQuery() メソッドは、特定の状況では、クライアント オブジェクト モデルによって、より効率的にクエリを処理でき、より効率的にメモリを使用できることを除いて、Load() メソッドと機能が似ています。また、より柔軟性のあるプログラムミングの方法も許可されています。

LoadQuery() メソッドは、Load() メソッドとは異なる形式を持ちます。Load() メソッドではサーバーからのデータがクライアント オブジェクト (またはクライアント オブジェクトのコレクション) に設定されますが、LoadQuery() メソッドでは、新しいコレクションに設定されて返されます。これは、同じオブジェクトのコレクションにクエリを複数回実行して、各クエリの結果セットを別々に保持できることを意味します。たとえば、特定の人に割り当てられたプロジェクトのリストのすべての項目を要求するクエリを実行し、それとは別に、特定のしきい値よりも推定時間が長いすべての項目を要求するクエリを実行して、両方の結果セットに同時にアクセスできます。また、これらのコレクションを範囲外にして、ガベージ コレクションの対象にすることもできます。Load() メソッドを使用して読み込むコレクションがガベージ コレクションの対象になるのは、クライアントのコンテキストの変数自体が範囲外になる場合のみです。これらの違いのほかは、LoadQuery() メソッドは Load() メソッドと同じ機能を提供します。

次の例では、LoadQuery() メソッドを使用してサイト内のすべてのリストの一覧を取得します。

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

LoadQuery() メソッドによって、反復処理できる新しいリストのコレクションが返されることに注意してください。新しいリストのコレクションは、ListCollection の代わりに IEnumerable<List> の型を持ちます。

LoadQuery() メソッドの形式で注意することが必要な点があります。上記の例では、元のリストの変数には、ExecuteQuery() メソッドによって返された後に設定されたプロパティの値がありません。そのリストに値を設定する場合は、Load() メソッドを明示的に呼び出して、読み込むプロパティを指定する必要があります。

LoadQuery での入れ子の Include ステートメントによるパフォーマンスの向上

LoadQuery() メソッドを呼び出す際に、読み込むプロパティの複数のレベルを指定できます。これによって、クライアント オブジェクト モデルによって SharePoint Foundation が実行されているサーバーが呼び出されて必要なデータが取得される必要がある回数が削減されることから、クライアント オブジェクト モデルで SharePoint Foundation が実行されているサーバーへのアクセスが最適化されます。次のクエリでは、サイトからすべてのリストが取得され、各リストからすべてのフィールドが取得されます。さらに、コンソールへ出力され、各リストや各フィールドが非表示の場合は通知されます。

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

この方法によって、クライアント オブジェクト モデルのサーバーの部分が、アプリケーションによって最初にリストの一覧が読み込まれてから各リストのフィールドが読み込まれるよりも、効率的になります。

LINQ を使用する LoadQuery によって返される子コレクションのフィルター処理

LoadQuery() メソッドで、IQueryable<T> の型のオブジェクトがパラメーターとして利用され、これによって、CAML の代わりに LINQ クエリを書いて結果のフィルター処理を行うことができます。この例では、非表示でないすべてのドキュメント ライブラリのコレクションが返されます。

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

クライアント オブジェクトの更新

クライアント オブジェクト モデルを使用したクライアント オブジェクトの更新は、非常に簡単です。オブジェクトを取得し、プロパティを変更し、変更する各オブジェクトの Update メソッドを呼び出して、ExecuteQuery() メソッドを呼び出します。次の例では、 Client API Test List内の項目を変更して、すべての開発項目の見積もりを 50 % 増やします (共通の操作)。

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

クライアント オブジェクトの削除

クライアント オブジェクトの削除も同様に簡単です。ただし、クライアント オブジェクトのコレクションからのクライアント オブジェクトの削除に関して非常に重要な点が 1 つあります。コレクションに反復処理を行って、オブジェクトを削除することはできません。最初のオブジェクトを削除すると、クライアント オブジェクトのコレクションの反復子が正しく機能しなくなります。反復子が例外をスローしたり、コレクションのすべてのアイテムの処理を行っていないのにエラーを発生させずに終了する場合があります。代わりに、ToList メソッドを使用して、コレクションを List<T> へ具現化して、そのリストに反復処理を行ってクライアント オブジェクトを削除する必要があります。

次の例では、 Client API Test Listからテスト用のアイテムを削除します。ToList メソッドを使用して反復処理の前にコレクションを実体化する方法を示します。

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

次のコード例では、正しくない方法を示します。

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();

最後に、Client API Test List を消去するために、リストとアイテムを削除する例を示します。

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

フィールドのスキーマの取得

前述したように、このセクションでは、リストで作成するフィールドの作成に使用する XML スキーマを取得する簡単な方法を説明します。まず、SharePoint サイトで、必要に応じて構成されている列を含むリストを作成します。その後で、次の例を使用して、それらのフィールドを作成する XML を出力できます。

次の例では、 Client API Test Listに追加したフィールドのフィールド スキーマを出力します。

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("===============");
            }
        }
    }
}

「リストの作成と入力」のセクションのプログラム例を使用してリストを作成した後にこれを実行すると、次の出力が生成されます。

<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" />
===============

この例では、フィールドの作成に必要ない属性は削除されます。

大きなリストへのアクセス

SharePoint の開発のガイドラインでは、1 回のクエリで 2000 以上の項目の取得を行わないようにすることが示されています。アプリケーションでその可能性がある場合は、CAML のクエリで RowLimit 要素を使用して、クライアント オブジェクト モデルによってアプリケーション用に取得されるデータの量を制限することを検討してください。2000 以上の項目を含んでいる可能性があるリストのすべての項目にアクセスする必要がある場合があります。その場合の最良の方法は、2000 個のアイテム全体のページングを一度に行うことです。このセクションでは、ListItemCollectionPosition プロパティを使用したページングの方法を説明します。

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

この例では、次の出力が生成されます。

  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

非同期処理

使用できない可能性がある SharePoint サイトに接続する必要があるアプリケーションを作成している場合、または、長い時間がかかる可能性があるクエリを定期的に実行する必要がある場合は、非同期処理の使用を検討する必要があります。これによって、クエリが別のスレッドで実行されている間も、アプリケーションはユーザーに応答できます。メインのスレッドでは、設定されたしきい値よりも長い時間がクエリにかかっている場合に通知するようにタイマーを設定でき、ユーザーにクエリの状態がわかるようにすることができ、最終的にクエリが終了したときに結果を表示できます。

クライアント オブジェクト モデルの JavaScript バージョンと、Silverlight バーション (ユーザー インターフェイスを変更する場合) では、非同期処理が使用されます。SharePoint 2010 SDK の「Data Retrieval Overview」のトピックに、JavaScript および Silverlight を使用した非同期処理の使用方法の例が含まれています。

Windows フォーム アプリケーション、WPF アプリケーションなどの .NET Framework をベースとした従来のアプリケーションを作成する場合は、非同期処理を使用することをお勧めします。次の例では、BeginInvoke メソッドが使用されて、クエリが非同期で実行されます。このコードでは、BeginInvoke メソッドにステートメント形式のラムダ式が渡されることに注意してください。このため、ステートメント形式のラムダ式が含まれるメソッドで、ステートメント形式のラムダ式から自動変数を参照できるので、このパターンの作成に便利です。ステートメント形式のラムダ式には、変数 clientContext と変数 newListCollection へのアクセスがあることがわかります。Microsoft Visual C# の完了によって、言語機能が適切に機能します。

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

この例では、以下のような出力が生成されます。

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

参考資料

詳細については、以下のリソースを参照してください。