SharePoint 2010 の REST を使用した操作 (Method) の一覧


2012/10 : ここでは SharePoint 2010 の REST API を紹介しています。SharePoint 2013 以降では新しい REST API (client.svc の REST API) が使用できるので、「Windows 8 store apps と SharePoint 2013 の連携アプリケーション開発」を参照してください。

環境 : SharePoint Server 2010 (または、Office 365), Visual Studio 2010, ASP.NET Web API (HttpClient, Json.NET) RC

こんにちは。

リモートから SharePoint 2010 に接続する方法は、「リモートからの SharePoint 接続 – REST の使用」 に記載しているように、以下の 3 種類の接続方法が提供されています。

  • XML Web サービス
  • REST Web サービス
  • クライアント オブジェクト モデル (Client OM)

補足 : 上記の クライアント オブジェクト モデル (Client OM) は、内部で、XML Web サービスを呼び出しています。

ここでは、2 番目の REST Web サービスを使用した SharePoint の操作 について記載します。

.NET のクライアントからの操作方法には、主に以下の 2 通りが考えられます。まずは、それぞれの特徴を記載しておきます。

  • WCF Data Services のユーティリティ :
    REST を .NET (Visual Studio) から操作する際に、一般的に使用される方法です。
    「リモートからの SharePoint 接続 – REST の使用」 に記載しているように、Visual Studio のソリューション エクスプローラーでプロジェクトをマウスで右クリックして、[サービス参照の追加...] メニューを選択して必要なクラスを自動作成します。(内部で、.NET SDK が提供する WCF Data Services のユーティリティ datasvcutil.exe が実行されます。)
  • HttpWebRequest、または HttpClient (ASP.NET Web API) の使用 :
    HTTP のプロトコルを処理するクライアント クラスを使用して接続します。既存の .NET ではお馴染みの HttpWebRequest クラスも使用できますが、下記では、REST (Web Api) の操作要求のために最適化された ASP.NET Web API (旧 WCF Web API) の HttpClient クラスを使用します。

上記の前者の方法 (WCF Data Services のユーティリティを使った方法) は、手順も容易で、直感的なプログラミングが可能ですが、静的な型の定義がおこなわれるという点に注意してください。上記の [サービス参照の追加...] によって、クライアント側に静的な型情報がコードとして生成されるため、リストのフィールドなどが決まっていないような不特定な情報に接続するケースには不向きです。(フィールドの追加など、構成を変更した場合には、再度、[サービス参照の更新] をおこなって定義を再作成する必要があります。)
それに対し、後者の方法 (ASP.NET Web API) では、提供されている HttpClient クラスや Json.NET (JObject, JValue 等) を使用して、後述するように、動的な型の解決が容易に実現できます。(リストやドキュメント ライブラリのフィールドの内容に関係なく、実行時に型の解決をおこなうことができます。)

以降では、それぞれの操作内容ごとに、使用される HTTP の内容と、上記の前者、後者のプログラミング手法 (サンプル コード) を紹介していきます。

なお、以下では、対象のフレームワークが .NET Framework 4 Client Profile の場合は、.NET Framework 4 に変更しておいてください。

また、今回、HttpClient の処理では Json を使用しますが、WCF Data Services のユーティリティ を使用した手法では、内部で、必ず Atom フォーマットが使用されるので注意してください。

補足 (2012/10 追記) : WCF Data Services 5.1 から、Json によるデータ交換が可能です。下記の通り記述します。(下記では、Accept ヘッダーを使って application/json を要求します。)

Uri svcUri = new Uri("http://machine01/test1.svc", UriKind.Absolute);
PersonContext context = new PersonContext(svcUri);
context.UseJsonFormatWithDefaultServiceModel();
. . .

 

[操作] リスト アイテムの一覧の取得

HTTP リクエスト

リスト TestList1 から、リスト アイテムの一覧を JSON フォーマットで取得します。

GET http://machine01/sites/test1/_vti_bin/listdata.svc/TestList1() HTTP/1.1
Accept: application/json    <- json の場合は、このヘッダーを入れます (以降、同様に記述)

補足 : リスト名、フィールド名などが日本語の場合には、URL エンコードをおこなってください。(空白文字も %20 となります。ここでは、すべて、英語の名称を使用しています。)
以降も同様です。

プログラミング - HttpClient (ASP.NET Web API)

以下では、HttpClient を使用して、取得したリスト アイテム (すべて) の Title を表示します。

. . .
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Formatting;
using Newtonsoft.Json.Linq;
. . .

string uri =
  "http://machine01/sites/test1/_vti_bin/listdata.svc/TestList1()";
HttpClientHandler handler = new HttpClientHandler();
handler.Credentials =
  new System.Net.NetworkCredential(
    "demouser",
    "password01");
HttpClient cl = new HttpClient(handler);
cl.DefaultRequestHeaders.Accept.Add(
  new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage res = cl.GetAsync(uri).Result;
JObject jreturn =
  res.Content.ReadAsAsync<JObject>(new[] { new JsonMediaTypeFormatter() }).Result;
JObject jd = (JObject) jreturn["d"];
JArray jresults = (JArray) jd["results"];
foreach (JObject item in jresults)
  Console.WriteLine(
    "{0}",
    ((JValue) item["Title"]).Value);

補足 : Json.NET について
JObject は json オブジェクト、JValue は Json で扱える Primitive な値 (文字列、数値など)、JArray は json の配列です。すべて JToken から継承されています。(なお、JValue では、
json にはない日付型も扱えます。SharePoint などと同様のシリアライズ方法 (OData) が採用されています。)
デバッグなどの際は、ToString() メソッドで json の文字列そのものが確認できます。(JToken で取得して ToString すれば、どんな結果も確認できます。)

補足 : ASP.NET Web API の MediaTypeFormatter について
ASP.NET Web API では、MediaTypeFormatter から継承された Formatter を登録 (プラグイン) することで、さまざまなフォーマットに対応した Web API を扱えるようになっています。上記では、既定で提供されている JsonMediaTypeFormatter (Json フォーマットを扱う MediaTypeFormatter) を使用しています。

補足 : エラーが発生した場合のメッセージも Json で返ってくるため、実際の開発では、こうした処理もおこなってください。なお、日本語は URL エンコードされます。
以降も同様です。

プログラミング - WCF Data Services

上記と同じ処理を WCF Data Services の DataServiceContext で記述すると以下の通りになります。(下記の Test1_DataContext は、datasvcutil.exe が生成した DataServiceContext クラスです。)

ServiceReference1.Test1_DataContext dc = new ServiceReference1.Test1_DataContext(new Uri("http://machine01/sites/test1/_vti_bin/listdata.svc"));
dc.Credentials = new System.Net.NetworkCredential("demouser", "p@ssword01");
var res = from d in dc.TestList1
            select d;
foreach (var item in res)
    Console.WriteLine("{0}", item.Title);

補足 : 上述の通り、この方法では、内部で Atom (application/atom+xml) が使用されます。(Json は使用できません。)
以降も同様です。

 

[操作] リスト アイテムの検索

下記では、Title に "SharePoint" の文字列が含まれ、EventDate が 2011-04-10 以降の、TestList1 のアイテム一覧を取得します。

HTTP リクエスト

GET http://machine01/sites/test1/_vti_bin/listdata.svc/TestList1()?$filter=substringof('SharePoint',Title)%20and%20(EventDate%20gt%20datetime'2011-04-10T00%3A00%3A00') HTTP/1.1
Accept: application/json

プログラミング - HttpClient (ASP.NET Web API)

. . .
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Formatting;
using Newtonsoft.Json.Linq;
. . .

string uri =
  @"http://machine01/sites/test1/_vti_bin/listdata.svc/TestList1()?$filter=substringof('SharePoint',Title) and (EventDate gt datetime'2011-04-10T00:00:00')";
HttpClientHandler handler = new HttpClientHandler();
handler.Credentials =
  new System.Net.NetworkCredential(
    "demouser",
    "password01");
HttpClient cl = new HttpClient(handler);
cl.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage res = cl.GetAsync(uri).Result;
JObject jreturn = res.Content.ReadAsAsync<JObject>(new[] { new JsonMediaTypeFormatter() }).Result;
JObject jd = (JObject)jreturn["d"];
JArray jresults = (JArray)jd["results"];
foreach (JObject item in jresults)
  Console.WriteLine(
    "{0}",
    ((JValue)item["Title"]).Value);

プログラミング - WCF Data Services

ServiceReference1.Test1_DataContext dc = new ServiceReference1.Test1_DataContext(new Uri("http://machine01/sites/test1/_vti_bin/listdata.svc"));
dc.Credentials = new System.Net.NetworkCredential("demouser", "p@ssword01");
var res = from d in dc.TestList1
            where d.Title.Contains("SharePoint") & (d.EventDate > new DateTime(2011, 4, 10))
            select d;
foreach (var item in res)
    Console.WriteLine("{0}", item.Title);

 

[操作] リスト アイテムの結合 (リレーション) の展開

下記では、リスト TitleList1 に、Owner という名前の参照列 (他のリストを参照している列) が設定されており、この参照列を展開して、参照先の Name フィールドを取得しています。

HTTP リクエスト

GET http://machine01/sites/test1/_vti_bin/listdata.svc/TestList1()?$expand=Owner&$select=Title,Owner/Name HTTP/1.1
Accept: application/json

プログラミング - HttpClient (ASP.NET Web API)

. . .
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Formatting;
using Newtonsoft.Json.Linq;
. . .

string uri =
  @"http://machine01/sites/test1/_vti_bin/listdata.svc/TestList1()?$expand=Owner&$select=Title,Owner/Name";
HttpClientHandler handler = new HttpClientHandler();
handler.Credentials =
  new System.Net.NetworkCredential(
    "demouser",
    "password01");
HttpClient cl = new HttpClient(handler);
cl.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage res = cl.GetAsync(uri).Result;
JObject jreturn = res.Content.ReadAsAsync<JObject>(new[] { new JsonMediaTypeFormatter() }).Result;
JObject jd = (JObject)jreturn["d"];
JArray jresults = (JArray)jd["results"];
foreach (JObject item in jresults)
{
  Console.WriteLine(
    "{0}",
    ((JValue)item["Title"]).Value);
  JObject owner = (JObject)item["Owner"];
  Console.WriteLine(
    "{0}",
    ((JValue)owner["Name"]).Value);
}

プログラミング - WCF Data Services

ServiceReference1.Test1_DataContext dc = new ServiceReference1.Test1_DataContext(new Uri("http://machine01/sites/test1/_vti_bin/listdata.svc"));
dc.Credentials = new System.Net.NetworkCredential("demouser", "p@ssword01");
var res = from d in dc.TestList1
            select new { d.Title, d.Owner.Name };
foreach (var item in res)
{
    Console.WriteLine("{0}", item.Title);
    Console.WriteLine("{0}", item.Name);
}

 

[操作] リスト アイテムの作成

下記では、リスト TestList1 に、リスト アイテムを作成 (追加) します。

HTTP リクエスト

POST http://machine01/sites/test1/_vti_bin/listdata.svc/TestList1 HTTP/1.1
Accept: application/json
Content-Type: application/json; charset=utf-8

{"Title":"Office 365 開発者会議","EventDate":"2011-04-27T15:30:00.000"}

プログラミング - HttpClient (ASP.NET Web API)

. . .
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Formatting;
using Newtonsoft.Json.Linq;
. . .

string uri = @"http://machine01/sites/test1/_vti_bin/listdata.svc/TestList1";
HttpClientHandler handler = new HttpClientHandler();
handler.Credentials =
  new System.Net.NetworkCredential(
    "demouser",
    "password01");
HttpClient cl = new HttpClient(handler);
cl.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
JObject newObj = new JObject();
newObj.Add("Title", new JValue("Office 365 開発者会議"));
newObj.Add("EventDate", new JValue(new DateTime(2011, 4, 27, 15, 30, 0)));
HttpContent jsonContent = new StringContent(
  newObj.ToString(),
  Encoding.UTF8,
  "application/json");
HttpResponseMessage res = cl.PostAsync(uri, jsonContent).Result;

プログラミング - WCF Data Services

ServiceReference1.Test1_DataContext dc = new ServiceReference1.Test1_DataContext(new Uri("http://machine01/sites/test1/_vti_bin/listdata.svc"));
dc.Credentials = new System.Net.NetworkCredential("demouser", "p@ssword01");
ServiceReference1.TestList1Item newItem = new ServiceReference1.TestList1Item();
newItem.Title = "Office 365 開発者会議";
newItem.EventDate = new DateTime(2011, 4, 27, 15, 30, 0);
dc.AddObject("TestList1", newItem);
dc.SaveChanges();

 

[操作] リスト アイテムの変更

下記では、リスト TestList1 の特定のリスト アイテムを変更します。

HTTP リクエスト

PUT http://machine01/sites/test1/_vti_bin/listdata.svc/TestList1(1) HTTP/1.1
Accept: application/json
If-Match: *
Content-Type: application/json; charset=utf-8

{"Title":"Office 365 開発者会議","EventDate":"2011-04-27T15:00:00.000"}

補足 : PUT はアイテム全体を変更します。これに対し、指定したフィールドのみを変更する場合 (他のフィールドは変更しない場合) には、MERGE メソッド (または、PATCH メソッド) を使用します。

補足 : URL には、そのアイテムの Uri を設定します。(上記は、識別子 (ID) が 1 のアイテムの Uri です。) この Uri は、取得したアイテムの JObject 内の __metadata の uri キーから取得できます。
MERGE メソッド (PATCH メソッド)、DELETE メソッドにおいても同様です。

補足 : 同時実行制御について
上記の If-Match ヘッダーは重要です。OData では、常に、読み込み時にロックをかけずに更新処理をおこなう楽観的同時実行制御 (optimistic concurrency management) が採用されます。このため、OData では、更新処理の競合を回避する目的で、アイテムが更新 (作成 / 変更) される度に ETag と呼ばれるバージョン管理のための値を割り当てます。クライアントは、読み込み時に アイテムの ETag の値を取得し、変更時には、この取得した ETag の値を If-Match ヘッダーに設定することで、アイテムの読み込みをおこなった時点と同じ内容である (つまり、読み込みをおこなった時点からアイテムが変更されていない) ことをサーバー側で検証し、競合なく更新処理をおこなうことができます。(ETag が一致しない場合は、エラーが発生します。)
一方、上記の通り If-Match ヘッダーに * を設定すると、この検証はおこなわず、強制的に上書きがおこなわれます。
(これらは、MERGE メソッド、DELETE メソッドにおいても同様です。)
2011/09/29 追記 : この内容については、「Web API / REST サービスにおける同時実行制御」に記載しました。

プログラミング - HttpClient (ASP.NET Web API)

. . .
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Formatting;
using Newtonsoft.Json.Linq;
. . .

string uri = @"http://machine01/sites/test1/_vti_bin/listdata.svc/TestList1(1)";
HttpClientHandler handler = new HttpClientHandler();
handler.Credentials =
  new System.Net.NetworkCredential(
    "demouser",
    "password01");
HttpClient cl = new HttpClient(handler);
cl.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
cl.DefaultRequestHeaders.IfMatch.Add(EntityTagHeaderValue.Any);
JObject updateObj = new JObject();
updateObj.Add("Title", new JValue("Office 365 技術者会議"));
updateObj.Add("EventDate", new JValue(new DateTime(2011, 4, 27, 15, 00, 0)));
HttpContent jsonContent = new StringContent(updateObj.ToString(), Encoding.UTF8, "application/json");
HttpResponseMessage res = cl.PutAsync(uri, jsonContent).Result;

補足 : 上記の IfMatch プロパティについては、上記 (If-Match ヘッダー) を参照してください。(以降も同様です。)

プログラミング - WCF Data Services

ServiceReference1.Test1_DataContext dc = new ServiceReference1.Test1_DataContext(new Uri("http://machine01/sites/test1/_vti_bin/listdata.svc"));
dc.Credentials = new System.Net.NetworkCredential("demouser", "p@ssword01");
var res = from d in dc.TestList1
          where d.ID == 1
          select d;
ServiceReference1.TestList1Item item = res.FirstOrDefault<ServiceReference1.TestList1Item>();
item.Title = "Office 365 開発者会議";
item.EventDate = new DateTime(2011, 4, 27, 15, 00, 0);
dc.UpdateObject(item);
dc.SaveChanges();

補足 : このコードでは、内部で、If-Match ヘッダーとして ETag の値が設定されます。(アイテムのバージョンの検証がおこなわれます。)
以降も同様です。

 

[操作] リスト アイテムの削除

下記では、リスト TestList1 の特定のリスト アイテムを削除します。

HTTP リクエスト

DELETE http://machine01/sites/test1/_vti_bin/listdata.svc/TestList1(1) HTTP/1.1
Accept: application/json
If-Match: *

プログラミング - HttpClient (ASP.NET Web API)

. . .
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Formatting;
using Newtonsoft.Json.Linq;
. . .

string uri = @"http://machine01/sites/test1/_vti_bin/listdata.svc/TestList1(1)";
HttpClientHandler handler = new HttpClientHandler();
handler.Credentials =
  new System.Net.NetworkCredential(
    "demouser",
    "password01");
HttpClient cl = new HttpClient(handler);
cl.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
cl.DefaultRequestHeaders.IfMatch.Add(EntityTagHeaderValue.Any);
HttpResponseMessage res = cl.DeleteAsync(uri).Result;

プログラミング - WCF Data Services

ServiceReference1.Test1_DataContext dc = new ServiceReference1.Test1_DataContext(new Uri("http://machine01/sites/test1/_vti_bin/listdata.svc"));
dc.Credentials = new System.Net.NetworkCredential("demouser", "p@ssword01");
var res = from d in dc.TestList1
          where d.ID == 1
          select d;
ServiceReference1.TestList1Item item = res.FirstOrDefault<ServiceReference1.TestList1Item>();
dc.DeleteObject(item);
dc.SaveChanges();

 

[操作] ファイルの読み込み (ダウンロード)

HTTP リクエスト

ドキュメント ライブラリ DocLib1 から、バイナリのドキュメントをダウンロードします。

GET http://machine01/sites/test1/DocLib1/test1.docx HTTP/1.1
Accept: */*

プログラミング - HttpClient (ASP.NET Web API)

ドキュメント ライブラリ DocLib1 のアイテムを取得し、そのアイテムのバイナリ データの Uri (media_src) を取得して、そのバイナリ データ自身を取得 (GET) します。

. . .
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Formatting;
using Newtonsoft.Json.Linq;
using System.IO;
. . .

string uri = @"http://machine01/sites/test1/_vti_bin/listdata.svc/DocLib1(1)";
HttpClientHandler handler = new HttpClientHandler();
handler.Credentials =
  new System.Net.NetworkCredential(
    "demouser",
    "password01");
HttpClient cl = new HttpClient(handler);
cl.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage res = cl.GetAsync(uri).Result;
JObject jreturn = res.Content.ReadAsAsync<JObject>(new[] { new JsonMediaTypeFormatter() }).Result;
JObject jd = (JObject)jreturn["d"];
JObject jmeta = (JObject)jd["__metadata"];
string mediasrc = (string)((JValue)jmeta["media_src"]).Value;
cl.DefaultRequestHeaders.Accept.Clear();
cl.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
HttpResponseMessage resFile = cl.GetAsync(mediasrc).Result;
byte[] buf = new byte[1000];
FileStream wrSt = new FileStream(@"c:\Demo\tmp.docx",
  System.IO.FileMode.Create,
  System.IO.FileAccess.Write);
Stream rdSt = resFile.Content.ReadAsStreamAsync().Result;
while (rdSt.CanRead)
{
  int readsize = rdSt.Read(buf, 0, buf.Length);
  if (!(readsize > 0)) break;
  wrSt.Write(buf, 0, readsize);
}
wrSt.Close();

補足 : ここでは省略していますが、実際の開発では、Content-Type に応じたファイル名 (拡張子) の変更や、エンコード方法 (Base64 エンコード、など) に応じたデコード処理などをおこなってください。

プログラミング - WCF Data Services

上記と同じ処理を WCF Data Services の DataServiceContext で記述すると以下の通りになります。

. . .
using System.IO;
using System.Data.Services.Client;
. . .

ServiceReference1.Test1_DataContext dc = new ServiceReference1.Test1_DataContext(new Uri("http://machine01/sites/test1/_vti_bin/listdata.svc"));
dc.Credentials = new System.Net.NetworkCredential("demouser", "p@ssword01");
var res = from d in dc.DocLib1
          where d.ID == 1
          select d;
ServiceReference1.DocLib1Item item = res.FirstOrDefault<ServiceReference1.DocLib1Item>();
DataServiceStreamResponse stRes = dc.GetReadStream(item);
byte[] buf = new byte[1000];
FileStream fileSt = new FileStream(@"c:\Demo\tmp.docx",
    System.IO.FileMode.Create,
    System.IO.FileAccess.Write);
while (stRes.Stream.CanRead)
{
    int readsize = stRes.Stream.Read(buf, 0, buf.Length);
    if (!(readsize > 0)) break;
    fileSt.Write(buf, 0, readsize);
}
fileSt.Close();

 

[操作] ファイルの書き込み (アップロード)

下記では、ドキュメント ライブラリ DocLib1 にバイナリのドキュメント アイテムを作成 (追加) します。

HTTP リクエスト

POST http://machine01/sites/test1/_vti_bin/listdata.svc/DocLib1 HTTP/1.1
Accept: application/json
Content-Type: plain/text
Slug: /sites/test1/DocLib1/test.txt

<byte data of file . . .>

補足 : 登録されたアイテムの情報が Response として返ってきます。(上記の場合、この結果は Json フォーマットで返ってきます。) アイテムのプロパティ (タイトル、など) も細かく設定する必要がある場合は、この返ってきた値 (Response) を元に、引き続き、MERGE メソッドを使ってフィールド (プロパティ) を設定します。(下記の WCF Data Services を使用した方法では、内部で、この一連の処理がおこなわれています。)

補足 : ファイルの大きさなどに応じて、適宜、チャンク (chunk) をおこなってください。(チャンクをおこなう場合は、以下のヘッダーを追加して、コンテンツにバイト数に関する情報を埋め込みます。)
Transfer-Encoding: chunked

プログラミング - HttpClient (ASP.NET Web API)

. . .
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Formatting;
using Newtonsoft.Json.Linq;
using System.IO;
. . .

string uri = @"http://machine01/sites/test1/_vti_bin/listdata.svc/DocLib1";
HttpClientHandler handler = new HttpClientHandler();
handler.Credentials =
  new System.Net.NetworkCredential(
    "demouser",
    "password01");
HttpClient cl = new HttpClient(handler);
cl.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
FileStream fileSt = new FileStream(@"c:\Demo\tmp.txt",
  System.IO.FileMode.Open,
  System.IO.FileAccess.Read);
HttpContent fileContent = new StreamContent(fileSt);
fileContent.Headers.ContentType = new MediaTypeHeaderValue(@"plain/text");
fileContent.Headers.Add("Slug", "/sites/test1/DocLib1/test.txt");
HttpResponseMessage res = cl.PostAsync(uri, fileContent).Result;

補足 : HttClient でチャンクをおこなう場合は、下記の通り、TransferEncodingChunked プロパティを true に設定します。(HttpWebRequset を使用している場合は、SendChunked プロパティを true に設定します。)
cl.DefaultRequestHeaders.TransferEncodingChunked = true;

プログラミング - WCF Data Services

. . .
using System.IO;
using System.Data.Services.Client;
. . .

ServiceReference1.Test1_DataContext dc = new ServiceReference1.Test1_DataContext(new Uri("http://machine01/sites/test1/_vti_bin/listdata.svc"));
dc.Credentials = new System.Net.NetworkCredential("demouser", "p@ssword01");
ServiceReference1.DocLib1Item newItem = new ServiceReference1.DocLib1Item()
{
    ContentType = "plain/text",
    Title = "test",
    Name = "test",
    Path = "/sites/test1/DocLib1/test.txt"
};
dc.AddObject("DocLib1", newItem);
FileStream fileSt = new FileStream(@"c:\Demo\tmp.txt",
    System.IO.FileMode.Open,
    System.IO.FileAccess.Read);
dc.SetSaveStream(newItem, fileSt, false, "plain/text", "/sites/test1/DocLib1/test.txt");
dc.SaveChanges();

 

[操作] メタデータ (リスト、フィールド、など) の確認

使用可能なリスト (エンティティ) の一覧、リストのフィールド (エンティティのプロパティ) の一覧などのメタデータを取得します。(datasvcutil.exe を使用した場合は、あらかじめ、対応するリスト エンティティなどの .NET クラスが生成されますので、省略します。。。)

補足 : ただし、SharePoint 2010 の REST API では、正確なリスト名は取得できないので注意してください。 (空白文字が入っている場合など、エンティティ名はリスト名と同一にはなりません。) 厳密なリスト名を扱う場合には、SOAP Web Service を使用する必要があります。

HTTP リクエスト

GET http://machine01/sites/test1/_vti_bin/listdata.svc/$metadata HTTP/1.1

メタデータを取得する場合、Response は、必ず、application/xml で返されます。(Response を Json フォーマットで要求するとエラーになります。)
以下のフォーマットの Response が返ってきます。

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
  <edmx:Edmx Version="1.0"
    xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
    <edmx:DataServices . . .>
      <Schema Namespace="Microsoft.SharePoint.DataService"
        xmlns="http://schemas.microsoft.com/ado/2007/05/edm" . . .>
        <EntityType Name="TestList1Item">
          <Key>
            <PropertyRef Name="ID" />
          </Key>
          <Property Name="コンテンツタイプのID" Type="Edm.String" . . . />
          <Property Name="Title" Type="Edm.String" . . . />
          <Property Name="EventDate" Type="Edm.DateTime" . . . />
          . . .

        </EntityType>
        <EntityType Name="TestList2Item">...</EntityType>
        <EntityType Name="TestList3Item">...</EntityType>
        . . .

        <EntityContainer Name="Test1_DataContext" . . .>
          <EntitySet Name="TestList1" EntityType="Microsoft.SharePoint.DataService.TestList1Item" /> 
          <EntitySet Name="TestList2" EntityType="Microsoft.SharePoint.DataService.TestList2Item" /> 
          <EntitySet Name="TestList3" EntityType="Microsoft.SharePoint.DataService.TestList3Item" /> 
          . . .
        </EntityContainer>
        . . .

プログラミング - HttpClient (ASP.NET Web API)

以下は、上記のフォーマット (XML) のメタデータを解析して、特定のリスト (エンティティ) のフィールド (プロパティ) の一覧を取得するサンプルです。
上記の EntityContainer 要素に含まれる情報から EntityType を取得して、その EntityType 要素 (上記の <EntityType />) から Property の一覧を取得しています。

. . .
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Formatting;
using System.Xml.Linq;
. . .

string uri = "http://machine01/sites/test1/_vti_bin/listdata.svc/$metadata";
HttpClientHandler handler = new HttpClientHandler();
handler.Credentials =
  new System.Net.NetworkCredential(
    "demouser",
    "password01");
HttpClient cl = new HttpClient(handler);
cl.MaxResponseContentBufferSize = 1000000;
HttpResponseMessage res = cl.GetAsync(uri).Result;
XElement xmeta = res.Content.ReadAsAsync<XElement>(new[] { new XmlMediaTypeFormatter() }).Result;
XNamespace ns_edm_0705 = "http://schemas.microsoft.com/ado/2007/05/edm";
XNamespace ns_edmx_0706 = "http://schemas.microsoft.com/ado/2007/06/edmx";

// get entity information of a list (using list name)
var metaEnt = (from x in xmeta.Element(ns_edmx_0706 + "DataServices").Element(ns_edm_0705 + "Schema").Element(ns_edm_0705 + "EntityContainer").Elements(ns_edm_0705 + "EntitySet")
        where x.Attribute("Name").Value == "TestList1"
        select x).FirstOrDefault<XElement>();

// get properties from list entity information
string nsPrefix = xmeta.Element(ns_edmx_0706 + "DataServices").Element(ns_edm_0705 + "Schema").Attribute("Namespace").Value;
var itemEnt = (from x in xmeta.Element(ns_edmx_0706 + "DataServices").Element(ns_edm_0705 + "Schema").Elements(ns_edm_0705 + "EntityType")
        where nsPrefix + "." + x.Attribute("Name").Value == metaEnt.Attribute("EntityType").Value
        select x).FirstOrDefault<XElement>();
foreach (var prop in itemEnt.Elements(ns_edm_0705 + "Property"))
{
  Console.WriteLine("Name:{0} Type:{1}",
    prop.Attribute("Name").Value,
    prop.Attribute("Type").Value);
}

補足 : HttpClient の既定のレスポンス バッファ サイズは 65536 バイトです。上記の通り、メタデータの情報を取得できるよう、十分なバッファ領域を確保してください。(HttpClient クラスの MaxResponseContentBufferSize プロパティを使用します。)

 

なお、OData で使用可能なオペレーターや演算子などについては以下に記載されていますので、是非 参考にしてみてください。

MSDN : Open Data Protocol by Example

http://msdn.microsoft.com/en-us/library/ff478141.aspx

 

Comments (2)

  1. 怜音 says:

    大変参考にさせて頂いています。

    アイテム更新をMergeメソッドで更新しようとしているのですが、WCF Web APIではMergeメソッドは非対応でしょうか?

  2. ご無沙汰しております!

    「WCF Web API の HttpClient で Merge メソッドに対応しているか」というご質問ですよね。

    ご指摘の通り、MERGE メソッドは、"専用のメソッド" は提供されていないのですが、以下のように、自身でメソッド名を指定することで利用可能です。

    HttpClient cl = new HttpClient();

    HttpMethod method = new HttpMethod("MERGE");

    HttpRequestMessage req = new HttpRequestMessage(method, @"http://…");

    cl.Send(req);

    HTTP ヘッダーの指定なども同様ですが、よく使うものはあらかじめ提供していますが、それ以外のものについては開発者自身で独自に指定や拡張ができるようにしている、といった設計になっていますね。が、MERGE くらいは、確かにあらかじめほしいですね。。。

Skip to main content