January 2016
Volume 31 Number 1
Windows 10 - Windows 10 アプリでの OneDrive REST API の使用
Windows Phone 8 など、以前のフレームワークでは、非常に使いやすい SDK が OneDrive チームから提供されていましたが、開発者にはあまり自由度がありませんでした。たとえば、ログイン メカニズムを実現するには組み込みのボタン コントロールを使用するしかありませんでしたが、このボタン コントロールは外観も動作も変えることができませんでした。しかし、最も厄介だったのは、事前に定められたこのエクスペリエンスでさえ、そのコードをプラットフォーム間で共有できないことでした。
ところが、今回 OneDrive チームは HTTP 要求 (GET、POST、PUT など) を基礎にした最新の REST API を提供することになりました。これにより、さらに柔軟な方法で、大規模クラウド ファイル ストレージの操作や、おなじみのコード共有テクニックを駆使したクロスプラットフォーム コードの開発が可能になります。こうしたクロスプラットフォーム コードは、すべての Windows プラットフォームは当然のこと、Xamarin プラットフォームを使って iOS や Android 上で実行することもできます。
2 部構成の連載の第 1 部となる今回は、新しい OneDrive API を活用してユニバーサル Windows プラットフォーム (UWP) アプリをビルドする方法を解説します。まず、REST API が動作するしくみと、開発者に求められる REST API の扱い方を紹介します。次に、ユーザーが OAuth を使用してシステムにログインする方法や、ファイル システム操作 (フォルダーの参照、ファイル情報の取得、ファイル コンテンツの入手、ファイルのアップロードなど) を利用する方法について見ていきます。さらに、アプリ フォルダーへのアクセスや、アイテムへのリンクを友人と共有するなど、細かい操作を実行する方法も調べます。
第 2 部では、OneDrive チームの新しいポータブル クラス ライブラリ (PCL) を取り上げる予定です。PCL は、今回説明する操作を便利なライブラリにカプセル化したもので、自身の UWP アプリに追加することができます。また、ASP.NET、Xamarin.iOS、Xamarin.Android、Xamarin.Form など、サポート対象のフレームワークでも使用できます。
注: Xamarin.Android と Xamarin.iOS については、この 2 つのプラットフォームで使用できる PCL に加え、OneDrive チームによってネイティブ SDK も提供されています。
サンプル コード
サンプル コードは galasoft.ch/s/msdnonedrive からダウンロードできます。このコードをご覧いただけば、簡単な UWP アプリから低レベルの REST API を使用して、OneDrive サービスの操作を実行する方法がわかります。コードを他のプラットフォームでも簡単に利用できることをデモするために、この同じアプリを Xamarin.Android にも実装します。この実装原理は他のプラットフォームにも当てはめることができます。
REST API について
REST API は HTTP をトランスポート プロトコルとして使用しているため、このプロトコルのメソッド (GET、POST、PUT、DELETE など) や、標準エラー コード (200 Success、400 Bad request、500 Server error など) を利用します。API の各エントリ ポイントへは、パラメーターを含めることができる一意の URI を使ってアクセスできます。単純な GET メソッドとクエリ文字列を使用して情報をサービスに送り、結果を取得する場合もありますが、シリアル化されたなんらかのオブジェクトを JSON に POST して、もっと複雑な要求を組み立てる場合もあります。
REST API は以前よりも広く普及しており、十分に理解している方法で Web サービスと通信できるため、開発者にとってはとても便利です。特に重要なのは、REST API を使うと、移植可能なコンポーネントを C# で作成し、そのコンポーネントをサポート対象のすべてのプラットフォームで使用できるようになることです。もう 1 つの大きなメリットは、HTTP がテキストベースなので、要求がファイアウォールやプロキシを簡単に通過できるようになることです。
ただし、低レベルの HTTP メソッドでのやり取りには多くの作業が必要だと感じられるかもしれません。非同期プログラミングを使う最近の開発に不慣れな開発者にとっては特にそう感じられます。コールバックを使用して非同期クライアントをビルドするのはあまり楽なことではありません。入れ子が深くなったり、スレッド処理に問題が生じる恐れがあります。さいわいなことに、比較的最近の開発手法に HttpClient コンポーネントと async/await キーワードがあり、C# プログラマにとっては非同期クライアントのビルドが非常に簡単になっています。たとえば、OneDrive のミュージック フォルダーへのアクセスは非常に簡素化され、以下のように URI を構築して、GET 要求を送信するだけです。
var uri = new Uri(
"https://api.onedrive.com/v1.0/drive/special/music");
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", AccessToken);
var json = await client.GetStringAsync(uri);
受け取った JSON コードは、(JSON.NET ライブラリなどを使用して) シリアル化を解除して、アプリで使用する .NET オブジェクトを取得することができます。上記のコードでは、(確かにログインやエラー処理はないものの) 以前は複雑だった処理がシンプルかつスムーズになっているのがわかります。さらに、このコードは HttpClient がサポートする、Windows Presentation Foundation (WPF)、ASP.NET、Windows 10、Xamarin など、さまざまなプラットフォームで問題なく実行されます。
アプリの登録
OneDrive API を呼び出すには、その前にアプリを OneDrive デベロッパー センターに登録して構成し、クライアント ID キーを取得しておかなければなりません。登録のメカニズムについては bit.ly/1GPBaWL (英語) をご覧ください。
新しいアプリを登録する場合は、[API 設定] ページに移動し、[モバイル クライアント アプリ/デスクトップ クライアント アプリ] を [はい] に設定してください。他の設定はすべて既定のままで問題ありません。次に、[アプリケーション設定] ページでクライアント ID を取得し、後で使用するために記録しておきます。
以下のさまざまな用語と、各 ID が必要な理由を理解しておくことが重要です。
- クライアント ID: 自身の UWP アプリの一意 ID です。同じクライアント ID を使用して、複数のクライアント アプリを Microsoft サービスに接続することもできますが、一般的にはアプリごとに 1 つのクライアント ID を使用することが推奨されます。クライアント ID は、UWP アプリの名前やアイコンなど、UWP アプリの情報にリンクされます。このクライアント ID はアプリの作成時に生成され、決して変化することはありません。
- クライアント シークレット: UWP アプリを作成時に生成される一意 ID です。ただし、このコードはアプリの有効期間中に変化することがあります。たとえば、クライアント シークレットがハッキングされたと考えられる場合、新しいシークレットを作成して自身のアプリを更新すれば、ハッカーのアプリからのアクセスが拒否されます。クライアント シークレットが使用されるのは、主にサーバー アプリに限られます。
- ユーザー ID とパスワード: ユーザーはログイン時にユーザー名とパスワードの入力を求められます。OAuth のおかげで、ログイン操作はユーザーと OneDrive 間のみで行われ、クライアント アプリはこれを認識する必要がなくなります。実際にはこれは Web ビューを使用して実行され、Web ビュー内でログイン ダイアログ ボックスが表示されます。
- アクセス トークン: ユーザーがログインに成功すると、認証サービスからアクセス トークンが返されます。このトークンは一定時間 (60 分) しか有効ではありません。有効期間が過ぎると、ユーザーは再度ログインする必要があります。アクセス トークンを各要求と共に送信し、ユーザーが認証済みであることを証明する必要があります。OneDrive のドキュメントでは、この認証モードをトークン フロー (Token Flow) と呼んでいます。
- 更新トークン: アクセス トークンが期限切れになった場合にアクセス トークンを更新するために、このトークンをアプリから要求して保存できます。更新トークンは、アプリが長時間バックグラウンド モードで使用されており、ユーザーの操作を介さずに定期的にデータを更新する必要がある場合に有効です。この認証モードをコード フロー (CodeFlow) と呼びます。詳しくは、こちら (bit.ly/1MQ3KOb、英語) をご覧ください。今回は、実装が簡単なトークン フローのみを使用します。
試用版トークンの利用
最初に認証を実装しないで、REST 要求をいくつか簡単に試してみる場合は、OneDrive デベロッパー センターから 1 時間有効の試用版トークンを取得できます。このトークンを取得するには以下の手順に従います。
- bit.ly/1MQ3KOb (英語) にアクセスします。
- [Try it now] (試してみる) セクションに移動し、[Get Token] (トークンの取得) をクリックします。
- 必要に応じてサインインし、デベロッパー センターから自身の OneDrive アカウントにアクセスすることを許可します。
- ログインに成功したら、試用版トークンが Web のメイン ウィンドウに表示されます。
- 新しい UWP アプリに「TrialOneDrive」という名前を付けて作成します。
- MainPage.xaml を開き、TrialButton というボタンを追加します。
- MainPage.xaml.cs を開いて TrialButton の Click イベントのイベント ハンドラーを追加します (図 1 参照)。OneDrive の操作はすべて非同期なので、このイベント ハンドラーでは "async" キーワードを使用する必要があります。
- 図 1 のコードで、文字列 "YOUR TRIAL TOKEN" を OneDrive デベロッパー センターの Web サイトからコピーした試用版トークンに置き換えます。"Authorization: bearer" の部分はコピーしません。
- JSON 変数を調べるために、イベント ハンドラーの最終行にブレーク ポイントを設定します。
- アプリを実行して、ボタンをクリックします。
- 取得した JSON コードをウォッチ ウィンドウで調べると、自身のミュージック フォルダーに関する情報を確認できます。たとえば、ミュージック フォルダーの名前、作成日、最終更新日、サブフォルダーの数、フォルダーの ID (後ほどさまざまなファイル システム操作で使用します)、ログイン ユーザー名などがわかります。
図 1 TrialButton の Click イベントのイベント ハンドラーを追加
TrialButton.Click += async (s, e) =>
{
var uri = new Uri(
"https://api.onedrive.com/v1.0/drive/special/music");
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", "YOUR TRIAL TOKEN");
var json = await client.GetStringAsync(uri);
};
試用版トークンは 1 時間で有効期限が切れるのを忘れないでください。したがって、このアプリのデモを上司に見せるつもりなら、忘れずに新しいトークンを取得してください。
OAuth による認証
登録済みのアプリを用意し、重要な用語について理解したところで、認証を実装してみます。認証は以下の手順に従います (図 2 参照)。
- たとえば、ユーザーがボタンをクリックして、認証を始めます。
- アプリは、アクセス トークンが有効かどうかをチェックします。
- アクセス トークンが有効ならば、アプリは既に認証済みなので、ユーザーは次の操作に移ります。アクセス トークンが無効ならば、アプリは Web ビューを含む XAML ページにユーザーを導きます。
- この XAML ページは、認証エンド ポイントのページを読み込むために、Web ビューの初期 URL を設定します。また、Web ビューの WebNavigationCompleted イベントのサブスクライブも行い、このコントロールでトラフィックを監視します。初期 URL を作成する方法については後ほどもう少し詳しく説明します。
- Web ビューが、認証エンドポイントから HTML を読み込みます。
- ユーザーが自身のユーザー名とパスワードを HTML 認証ページに入力します。このやり取りはユーザーと OneDrive サーバー間のみで行われることに注意してください。XAML ページは単なるコンテナーとして機能します。
- ユーザーが HTML のボタンをクリックすると、フォームが認証サーバーに送信されます。ユーザーが 2 要素認証を設定している場合は、2 要素認証を処理するページがさらに表示されます。
- 資格情報が正しければ、認証サーバーからログインに成功したことを示すために、Web ビューは特殊な URL にリダイレクトされます。この URL は、クエリ文字列パラメーターの 1 つとしてアクセス トークンも含みます。この XAML ページはリダイレクトが行われたことを検出するため、Web ビューの新しい URL からアクセス トークンを解析できます。
- 認証ページが、リダイレクトされた URI のアクセス トークンを解析します。
- アプリは元の XAML ページに戻ります。アクセス トークンは後の要求のために保存されます。
図 2 OAuth ワークフロー
注: OAuth のしくみを理解しておくことも重要ですが、さいわい、 Windows 10 の開発者には WebAuthenticationBroker というもっと簡単な代替手段があります。今回は "低レベル" OAuth メカニズムを使用し、WebAuthenticationBroker については次回に取り上げます。
スコープについて
ユーザーがログインするときに、アプリは必要な機能の範囲を OneDrive サービスに通知する必要があります。そのためには、認証 URL でスコープを指定します。OneDrive サービスでは、現在のところ以下のスコープがサポートされます。
- シングル サインオン (wl.signin)
- オフライン アクセス (wl.offline_access): アプリが更新トークンを取得できるようにします。トークン フローの使用時は、このスコープは無視されます。
- 読み取り専用アクセス (onedrive.readonly): アプリからファイルやフォルダーへの読み取り専用アクセスを可能にします。アプリがファイルの変更 (新しいファイルのアップロード) を試みると、サービスからエラー コード「403 Forbidden」が返ります。
- 読み書き可能アクセス (onedrive.readwrite): アプリからファイルやフォルダーへの読み取り/書き込みアクセスを可能にします。
- アプリフォルダー (onedrive.appfolder): いわゆるアプリ フォルダーにアプリからアクセスできるようにします。この特別なフォルダーの詳細については、後ほど説明します。このスコープは onedrive.readwrite スコープを要求すると自動的に許可されます。ただし、onedrive.appfolder を明示的に要求すると、このスコープについて示したダイアログ ボックスが表示されます。 (図 3 参照)。UX としてはこちらの方が適切でしょう。
図 3 認証の開始
if (!_service.CheckAuthenticate(
async () =>
{
var dialog = new MessageDialog("You are authenticated!", "Success!");
await dialog.ShowAsync();
Frame.GoBack();
},
async () =>
{
var dialog = new MessageDialog("Problem when authenticating!", "Sorry!");
await dialog.ShowAsync();
Frame.GoBack();
}))
{
Frame.Navigate(typeof (AuthenticationPage));
};
ユーザーが認証用 Web ページで自身の資格情報を入力すると、図 4 のようなダイアログ ボックスが表示され、アプリが要求しているアクセス許可の確認を求められます。ユーザーはいつでもこのアクセス許可の一部を無効にすることができます。そのためには、OneDrive Web サイトから自身のアカウントにログインし、[セキュリティとプライバシー] ページに移動して、[アプリとサービス] の下の [アクセス許可の管理] をクリックします。このサンプルでは、シングル サインオン、読み書き可能、およびアプリフォルダーのアクセス許可が常に要求されます。
図 4 認証の確認
初期 URL の作成
認証プロセスを開始するために使用する URL には、アプリ自体、要求される機能 (スコープ)、認証モード、およびリダイレクト URI についての情報が格納されている必要があります。
認証モードにはトークン フローとコード フローがあります。今回のサンプルではトークン モードを使用します。ユーザーは新たにアプリを開始するたび、または 1 時間が経過したらログインを確認する必要があります。これは面倒なように思えますが、実際には図 4 に示すように、ユーザー側で必要なのは認証ダイアログ ボックスで [Yes] (はい) をクリックすることだけです。
リダイレクト URI は、ログイン成功時に OneDrive サービスがアプリをリダイレクトするアドレスです。Web アプリの場合は自身のアプリの URI で、OneDrive デベロッパー センターの [API 設定] タブで構成します。しかし、UWP アプリの場合は、このフィールドを空欄にして、代わりに、以下の定義済みのリダイレクト URI を使用します。
htt://login.live.com/oauth20_desktop.srf
処理の全容
OAuth に準拠した認証が機能するしくみを理解したところで、コードを見ていきましょう。今回のシンプルなサンプル アプリでこのしくみを確認するには、[Authenticate] (認証) をクリックします。
OneDriveService というクラスを使用します。このクラスは、PCL にも実装します。OneDriveService のインスタンスは App.xaml.cs で作成し、クライアント ID を渡します。
まず、MainPage は OneDrive サービスに対する認証を既に済ませているかどうかを確認します。つまり、アクセス トークンが既に存在するかどうかを確かめます。認証に成功した場合に呼び出すアクションと、エラーの場合のアクションを示す 2 つのデリゲートを CheckAuthenticate メソッド呼び出しに渡します。
サービスがまだ認証されていない場合、MainPage は Frame プロパティを使用して AuthenticationPage に移動します (図 5 を参照)。このページは Web ビューを全画面表示する簡単な XAML ページで、ユーザーはここで自身のユーザー名とパスワードを入力して確認します。
図 5 AuthenticationPage のコード
public sealed partial class AuthenticationPage
{
private readonly OneDriveService _service;
public AuthenticationPage()
{
InitializeComponent();
_service = ((App)Application.Current).ServiceInstance;
Loaded += (s, e) =>
{
var uri = _service.GetStartUri();
Web.Navigate(uri);
};
Web.NavigationCompleted += (s, e) =>
{
if (_service.CheckRedirectUrl(e.Uri.AbsoluteUri))
{
_service.ContinueGetTokens(e.Uri);
}
};
Web.NavigationFailed += (s, e) =>
{
_service.ContinueGetTokens(null);
};
}
}
ページが読み込まれるときに、OneDriveService から次の認証 URI を受け取ります。
https://login.live.com/oauth20_authorize.srf?client_id=000000004C169646&
scope=wl.signin+onedrive.readwrite+onedrive.appfolder&response_type=token&
redirect_uri=https%3A%2F%2Flogin.live.com%2Foauth20_desktop.srf
前述のとおり、この URI にはクライアント ID、クライアント シークレット、スコープ、リダイレクト URI など、必要な情報がすべて含まれています。
アクセス トークンは、Web ビューが数回リダイレクトされてから返されます。これは、Web ビューの NavigationCompleted イベントでリダイレクト URI が毎回チェックされるためです。oauth20_desktop.srf URI が最終的に検出された時点で、OneDriveService はクエリ文字列のパラメーターからアクセス トークンを取得します。クエリ文字列にはこれ以外の情報 (有効期限、トークンの種類、スコープ、ユーザー ID など) も渡されますが、今回は説明を簡単にするため利用しません。アクセス トークンを含むリダイレクト URI は以下に示すように短縮されています。
https://login.live.com/oauth20_desktop.srf?lc=1033#access_token=EwB4Aq1D...1iiZA%3d&
token_type=bearer&expires_in=3600&scope=wl.signin%20onedrive.readwrite%20onedrive.appfolder
%20onedrive.readonly&user_id=8e5323e8b7c7a0928d03e10811531234
ユーザーが認証されたら、アプリからファイルやフォルダーを操作できるようになります。今回は、少しの操作だけに注目しますが、原理を理解してしまえば、アプリを拡張して追加のサービスを含めるのは非常に簡単です。
ルート フォルダー
まず、ルート フォルダーについて説明します。このフォルダーは利用者の OneDrive に 1 つだけ存在し、他の各アイテムの親フォルダーになります。
OneDrive ドキュメントに示されているとおり、ルート フォルダー取得するには、GET /drive/root 要求を実行します。この要求によって bit.ly/1M5w4NV (英語) に記載されているような JSON 応答が返されます。この JSON 応答のシリアル化を解除し、含まれている情報をその後の要求に利用します。
ファイルとフォルダーの構造: ここで重要なのは、ファイル システムの構造を理解することです。OneDrive は、ファイルとフォルダーに関する情報を提供するファセットのシステムを利用します。たとえば、ファイルは画像にも写真にもなり得ます。そのため、画像の幅や高さ、写真を撮影したカメラの型など、ファイルに関する追加情報も提供できます。以下に現在利用できるファセットを示します。また、かっこの中は、そのファイルにとって最も重要なプロパティを含めています。
- アイテム (名前、ID、ダウンロード URL、親参照など)
- フォルダー (子の数)
- ファイル
- オーディオ (アルバム、アーティスト、ビット レート、再生時間、タイトルなど)
- 画像 (幅、高さ)
- 写真 (カメラ メーカー、型番、撮影日時)
- 動画 (再生時間、ビット レート、幅、高さ)
新しいファイルを OneDrive にアップロードすると、そのファイルが自動的に分析され、なんらかのメタデータが追加されます。たとえば、Word 文書は単なるファイルですが、カメラで撮影した写真はファイルでもあり、写真や画像でもあります。このようなファセットそれぞれに、上記に示したような、そのファイルに関する追加情報があります。
OneDrive サービスから取得した JSON 応答を分析するときに、これらの種類を C# のクラスにマップできます。JSON 応答を調べることで、アイテムがフォルダー、ファイル、画像、動画など、いずれに相当するかが非常に簡単にわかります。例として、図 6 にルート フォルダーの JSON 応答から抽出した内容を示します。folder プロパティに、そのフォルダーの子の数に関する情報が含まれているのがわかります。写真の情報を取得すれば、幅、高さ、カメラ メーカー、型番に関する情報がそれぞれ画像や写真のプロパティに含まれています。
今回のサンプル アプリでは、応答ファイル用フォルダーに含まれているクラスの JSON 応答のシリアル化を解除しました。これらのクラスがファセット システムにマップされます。
応答のしくみ理解したら、以下のコードを使用して、簡単にルート フォルダー情報にアクセスできるようになります。
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", AccessToken);
var uri = new Uri("https://api.onedrive.com/v1.0/drive/root");
var json = await client.GetStringAsync(uri);
var rootFolder = JsonConvert.DeserializeObject<ItemInfoResponse>(json);
コードの動作を見るには、今回の簡単なサンプルを実行し、[Authenticate] (認証) ボタンをクリックしてから、[Get Root Folder] (ルート フォルダーの取得) ボタンをクリックします。
フォルダーの子の取得: 図 6 に示すように、この応答にはルート フォルダーに関するメタ情報しか含まれていません。フォルダーの子の数はわかりますが、子の一覧を取得するにはもう 1 回要求を実行しなくてはなりません。これもまた OneDrive ドキュメントに記載されていますが、図 7 に示すように、/drive/items/{item-id}/children の GET を要求します。
図 6 ルート フォルダーの JSON 応答
{
"createdBy": {
"user": {
"displayName": "Laurent Bugnion",
"id": "fb0d8f9700498123"
}
},
"createdDateTime": "2010-11-27T17:09:25.513Z",
"id": "FB0D8F97004979CD!ABC",
"lastModifiedBy": {
"user": {
"displayName": "Laurent Bugnion",
"id": " fb0d8f9700498123"
}
},
"lastModifiedDateTime": "2015-10-04T14:36:36.217Z",
"name": "root",
"size": 178558187077,
"webUrl": "https://onedrive.live.com/?cid=fb0d8f9700498123",
"folder": {
"childCount": 18
}
}
図 7 子の一覧の取得
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", AccessToken);
var request = string.Format("/drive/items/{0}/children", info.Id);
var uri = new Uri(
"https://api.onedrive.com/v1.0"
+ request);
var json = await client.GetStringAsync(uri);
var response = JsonConvert.DeserializeObject<ParseChildrenResponse>(json);
return response.Value;
図 7 の JSON 応答は ParseChildrenResponse というクラスにシリアル化を解除しています。子の一覧を Value という JavaScript 配列にラップする JSON 応答に、このクラスを再度マップします。ParseChildrenResponse クラスを図 8 に示します。
図 8 ParseChildrenResponse クラス
public class ParseChildrenResponse
{
public IList<ItemInfoResponse> Value
{
get;
set;
}
[JsonProperty("@odata.nextLink")]
public string NextLink
{
get;
set;
}
}
それぞれの子が 1 つの ItemInfoResponse になります。そのため、この応答の扱い方と、それぞれの子がフォルダー、ファイル、写真、オーディオ ファイルなど、いずれになるかを調べる方法は先ほどと同じです。
フォルダー情報を取得してから、子の一覧を用意すると 2 つの呼び出しが必要になりますが、これを避けるため、以下の要求を使用することもできます。この要求を使用すれば、すべてを 1 回の呼び出しで実行できます。
GET /drive/items/root?expand=children
ページングについて: アクセスしたフォルダーの子の数が多い場合、OneDrive サービスから返される応答にすべての情報が含まれておらず、ページングが必要になることがあります。既定では、OneDrive サービスから返される子の最大数は 200 に制限されています。参照するフォルダーの子がこれよりも多い場合は、@odata.nextLink というプロパティが子の一覧に追加されます (図 8 参照)。このプロパティには、次の "ページ" を取得するためにアプリで実行する必要がある次の要求の URI が含まれています。UWP アプリの場合、サービスをすぐに呼び出して次ページのアイテムを取得するか (長い一覧は仮想化されるのでこれは問題なく機能します)、またはアプリに [More] (詳細情報) ボタンを追加して、ページ ナビゲーションを実装します。
サブフォルダーの参照: フォルダーの ID を取得すれば、次の要求を使用して、その ID のフォルダーを簡単に参照できます。
GET /drive/items/{item-id}
フォルダーの ID を既に取得していれば、この要求は非常に便利ですが、こうした情報を入手していない場合もあります。代わりにルートからの相対パスを使用する構文を使ってフォルダーの情報を取得することも可能です。この構文を図 9 に示します。
図 9 パスによるサブフォルダーの参照
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", AccessToken);
var request = string.Format("/drive/root:/{0}", path);
var uri = new Uri(
"https://api.onedrive.com/v1.0"
+ request);
var json = await client.GetStringAsync(uri);
var result = JsonConvert.DeserializeObject<ItemInfoResponse>(json);
return result;
アプリ フォルダー
OneDrive にはミュージック、ドキュメント、写真など、特殊なフォルダーがいくつかあります。最近導入された特殊フォルダーの 1 つがアプリ フォルダーです。これはアプリが使用する特殊なフォルダーで、ローミング設定の保存、アップロード、バックアップなどに使用できます。注意点として、アプリ フォルダーは保護されているわけでもなく、非表示にもなりません。実際にはアプリ フォルダーは、ユーザーの OneDrive ルート直下のる "アプリ" フォルダー内にあります。アプリのアプリ フォルダーは開発している OneDrive アプリと同じ名前になります。これは、クライアント ID を取得するためにアプリを登録したときに入力した名前です。OneDrive アプリの設定によっては、このアプリの名前がさまざまな言語にローカライズされる場合があるので注意してください。ユーザーは、OneDrive Web サイトまたは任意のアプリからアプリ フォルダーに完全にアクセスでき、その気になればアプリ フォルダーを削除することもできます。
アプリ フォルダーの概念が導入されるまで、アプリは設定やファイルを OneDrive ルート フォルダーやカスタム フォルダーに保存していました (そのようなアプリはまだ数多くあります)。こうしたアイテムをアプリ フォルダーに整理することではるかに分かりやすくなり、UX が改善されます。OneDrive ドキュメント (bit.ly/1MBUkS2、英語) に記載されているように、アプリ フォルダーの情報は以下のような要求で取得します。
GET /drive/special/approot
自身のアプリにアプリ フォルダーを実装するのは簡単です。
ファイルのダウンロード
ファイルのアップロードやダウンロードができなければ OneDrive の存在意義はありません。ここからは、このきわめて重要な処理を実行する方法について説明します。これは非常に簡単です。
ファイルのコンテンツをダウンロードするため、OneDrive は DownloadUrl を作成します。これは ItemInfoResponse のプロパティとして保存されます。ただし、この URL が有効なのは短時間に限られます。そのため、ファイル情報をキャッシュしても、最初のサービスからその情報を再度取得する必要が生じることがあります (図 10 参照)。
図 10 ファイル コンテンツのダウンロード
public async Task<Stream> RefreshAndDownloadContent(
ItemInfoResponse model,
bool refreshFirst)
{
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", AccessToken);
// Refresh the item's information
if (refreshFirst)
{
var request = string.Format("/drive/items/{0}", model.Id);
var uri = new Uri(
"https://api.onedrive.com/v1.0"
+ request );
var json = await client.GetStringAsync(uri);
var refreshedItem =
JsonConvert.DeserializeObject<ItemInfoResponse>(json);
model.DownloadUrl = refreshedItem.DownloadUrl;
}
var response = await client.GetAsync(model.DownloadUrl);
var stream = await response.Content.ReadAsStreamAsync();
return stream;
}
ファイル コンテンツ ストリームを取得したら、ローカルでの処理や保存などが可能になります。今回の簡単なサンプルでは、FileSavePicker を使用してユーザーにファイルを保存する場所を問い合わせています。
ファイルのアップロード
同様に、ファイルのストリームを取得すれば、ファイルのアップロードも非常に簡単です。Windows 10 でこれを行うには、FileOpenPicker など、StorageFile インスタンスを使用します。ストリームを読み込んだら、ファイルを OneDrive にアップロードできます。OneDrive ドキュメントに記載されているとおり、次の PUT 操作を使用します。
PUT /drive/items/{parent-id}:/{filename}:/content
HttpClient は HttpContent インスタンスを使用した PUT メソッドをサポートしています。今回の場合、ファイル ストリームそのものがあるので StreamContent インスタンスを使用できます。保存するのがテキスト ファイルのみの場合は StringContent なども使用できます。
サービスにもう 1 つ情報を渡す必要があります。ファイルを保存するフォルダーの ID です。図 11 に示す今回の簡単なサンプルでは parentId をアップロード メソッドに渡しています。PUT 操作によって返される JSON コンテンツはファイルの ID、Web URL、ダウンロード URL など、OneDrive に関するファイルの新しい情報が含まれています。
図 11 ファイル コンテンツのアップロード
var content = new StreamContent(stream);
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", AccessToken);
var uri = new Uri(
"https://api.onedrive.com/v1.0"
+ string.Format(
"/drive/items/{0}:/{1}:/content",
parentId,
fileName));
var response = await client.PutAsync(uri, content);
var json = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<ItemInfoResponse>(json);
return result;
ここで説明した簡易アップロードに加えて、OneDrive API では、マルチパートの再開可能なアップロード構文も用意されています。またこの簡易アップロードが機能するのはファイルが 100 MB 未満の場合です。ファイル サイズがこれよりも大きい場合は bit.ly/1PB31Cn (英語) のドキュメントを参照してください。
一意リンクの取得
今回最後に取り上げる操作は、アイテムの一意 "共有" リンクを取得する方法です。この操作は、電子メール、SMS、ソーシャル メディアなどを通じて友人に一意リンクを送信するのに役立ちます。図 12 にアイテムの ID を使用してこの情報を取得する方法を示します。このサンプルでは、ここまでのデモでアップロードしたファイルへのリンクを取得します。
図 12 共有リンクの取得
public async Task<LinkResponseInfo> GetLink(
LinkKind kind,
string fileId)
{
// LinkKind id View or Edit
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", AccessToken);
var request = string.Format("/drive/items/{0}/action.createLink", fileId);
var uri = new Uri(
"https://api.onedrive.com/v1.0"
+ request);
var requestJson = JsonConvert.SerializeObject(
new RequestLinkInfo
{
Type = kind.ToString().ToLower()
});
var content = new StringContent(
requestJson,
Encoding.UTF8,
"application/json");
var response = await client.PostAsync(uri, content);
var result = JsonConvert.DeserializeObject<LinkResponseInfo>(
await response.Content.ReadAsStringAsync());
return result;
}
OneDrive ドキュメントによると、この要求は、前に行った GET 要求とは若干異なり、サービスはより詳しい情報を必要とします。この "共有リンク" 要求は、POST /drive/items/{item-id}/action.createLink のようになります。サービスにポストする必要のある情報は、"view" や "edit" のようなリンクの種類を { "type": "view" } のような形式で設定した JSON スニペットです。
まとめ
今回取り上げなかった操作は、ファイルの削除、ファイルの内容の更新、変更の同期など、他にもいくつかあります。ただし、一般に、こうした操作はすべて同じパターンに従い、HttpClient、HTTP メソッド、および JSON を使用して実行できます。Microsoft .NET Framework の非同期プログラミングの進歩おかげで、サポート対象のフレームワークであればどれにでも、こうした操作を非常にスムーズかつ簡単に実装できます。Windows 10 はもちろん、WPF、Windows Phone、Xamarin.iOS、Xamarin.Android などもその対象です。これほど簡単に使用できるのなら、コンテンツのバックアップやローミング設定など、UWP アプリになんらかのクラウド操作を組み込まない理由はありません。次回は、OneDrive チームからリリースされたばかりの PCL を使用して、こうしたやり取りをいっそう簡単にする方法を説明します。
Laurent Bugnion は、大手企業の 1 つで、マイクロソフト テクノロジーのゴールド パートナーでもある IdentityMine のシニア ディレクターです。彼は、スイスのチューリッヒを拠点に活動しています。2010 年に Sams から出版された彼の書籍『Silverlight 4 Unleashed』は、『Silverlight 2 Unleashed』(Sams、2008 年) の先進的な続編に当たります。複数の出版物で記事を執筆しており、Microsoft MVP として 9 年目、Microsoft Regional Director として 2 年目を迎えます。また、著名なオープン ソース フレームワーク、Windows、WPF、および Xamarin 用 MVVM Light の開発者であり、MVVM Light に関する人気の Pluralsight リファレンス コースの作成者でもあります。連絡先については、彼のブログ (galasoft.ch、英語) を参照してください。
この記事のレビューに協力してくれた技術スタッフの Corrado Cavalli (Gaia) および Ryan Gregg (マイクロソフト) に心より感謝いたします。