Open Data Protocol
OData を使用してあらゆるデバイスで優れたエクスペリエンスを構築する
Shayne Burgess
今月は、今日多くの組織が直面しているデータに関する深刻な課題を紹介し、Open Data Protocol (OData) およびそのエコシステムがこうした課題にどのように役立つかを説明します。さらに話を進めて、Windows Phone 7.1 (コードネーム "Mango") ベータ版向けの新しい OData ライブラリを使って、Windows Phone 7 での優れたエクスペリエンスの構築に OData を使用する方法について説明します。
データ アクセスの課題
2010 年の終わり、スマートフォンの出荷台数が PC の出荷台数を歴史上初めて上回るという興味深い出来事が起こりました。ここで注目すべき重要な点は、それが単独のレースではなく、数多くの組織 (Apple Inc.、Google Inc.、Microsoft、Research In Motion Ltd. など) とプラットフォーム (デスクトップ、Web、電話、タブレット、その他絶えず登場し続けるプラットフォーム) が関わるレースであるということです。多くの組織が、これらすべてのデバイスまたはほとんどのデバイスにおけるクライアント エクスペリエンスをターゲットにしており、クライアント デバイスに提供するさまざまなデータやサービスを用意している組織も多数あります。こうしたデータやサービスは、社内設置型で、従来の Web サービスを通じて利用可能なものもあれば、クラウド内に構築されるものもあります。
多様化を続ける大規模クライアント プラットフォームに、これも多様化を続ける大規模サービスを提供するには、甚大なコストと複雑性の問題が生み出されます。新たなクライアント プラットフォームに対するサポートを追加すると、多くの場合、そのプラットフォームをサポートするためにデータやサービスを更新および変更する必要があります。また、新たなサービスの追加に際し、そのサービスをサポートするために既存のクライアント プラットフォームすべてに変更を加える必要があります。これが、ここで話題にするデータ アクセスに関する問題です。既存のすべてのクライアントのエクスペリエンス、さらにはまだ開発されてもいない新しいクライアントのエクスペリエンスのニーズを満たせるような柔軟性のあるサービスは定義できるのでしょうか。さまざまなサービスおよびデータ ソースを操作できるクライアント ライブラリやアプリケーションは定義できるのでしょうか。こうした大きな疑問点のいくつかは、これから紹介する OData を使用して部分的に対処することが可能です。
Open Data Protocol
OData とは、データの照会および更新のための Web プロトコルで、データのロック解除に統一の手法を提供します。簡単に言うと、OData は、データ転送の標準形式とそのデータへのアクセスの統一インターフェイスを提供します。OData は、ATOM フィードと JSON フィードを基盤とし、データの照会や更新の機能の公開に HTTP (REST) インターフェイスを使用します。柔軟性のある統一インターフェイスにより、一度作成した API をさまざまなクライアント エクスペリエンスに使用できるため、OData はデータ アクセスの問題に対処する際の重要なコンポーネントになります。
OData のエコシステム
多種多様なクライアントから使用できる柔軟性を備えた OData は、既存の OData 対応クライアントを使用して構築されているさまざまなクライアント エクスペリエンスが存在する場合に最も威力を発揮します。ここ数年の間に、OData クライアントのエコシステムは、大部分のクライアント デバイスやクライアント プラットフォームにクライアント ライブラリが用意されているという状態まで進化しています。図 1 は、この記事の執筆時点で利用できるクライアント プラットフォームおよびサーバー プラットフォームを集めたものです (既存の OData サービスのより完全な一覧については、odata.org/producers (英語) を参照してください)。
図 1 OData のエコシステム
クライアント |
.NET |
Silverlight |
Windows Phone |
WebOS |
iPhone |
DataJS |
Excel |
Tableau |
サービス |
Windows Azure |
SQL Azure |
DataMarket |
SharePoint |
SAP |
Netflix |
eBay |
Wine.com |
通常は、図 1 に示したサービスをすべてのクライアントのターゲットにすることができます。このデモを行うため、異なるクライアントをいくつか使用して OData の柔軟性の例を示します。
ここでは、odata.org の http://services.odata.org/Northwind/Northwind.svc/ (英語) で入手できるサンプルの Northwind OData (読み取り専用) サービスを利用します。Northwind データベースを使い慣れていれば、図 2 に示す Northwind サービスにより、Northwind モデルを OData サービスとして単純に公開します。図 2 は、Northwind サービスのサービス ドキュメントをブラウザーで表示したものです。サービス ドキュメントはサービスのエンティティ セットを公開しますが、ここでのエンティティ セットは基本的には Northwind データベースのテーブルにすぎません。
図 2 Northwind サービス
Northwind OData サービスを使ったエクスペリエンスを使用および構築するためにクライアント ライブラリを使用する例をいくつか見てみましょう。最初の例では、コードのビルドを必要としないクライアント エクスペリエンスを考えます。Excel 用の PowerPivot アドインでは、直接 Excel のインターフェイスから利用できるメモリ内分析エンジンおよび OData フィードからデータを直接インポートするサポートが提供されます。PowerPivot アドインには、Windows Azure Marketplace DataMarket や、その他の多くのデータ ソースからデータを直接インポートするサポートも含まれています。
図 3 は、Northwind OData サービスから Products テーブルと Orders テーブルのデータをインポートし、その結果を結合して作成したピボット グラフを示しています。注文明細の単価のフィールドと数量のフィールドを組み合わて注文ごとに合計価格を算出後、その合計の平均値を製品ごとにグループ化し、分析用に簡単なピボット グラフに表示しています。これらはすべて、PowerPivot および Excel の組み込みインターフェイスやツールを使用して行われます。
図 3 PowerPivot アドイン
次は、別のプラットフォーム (iOS) で OData のクライアント エクスペリエンスを構築する方法の例を見てみましょう。iOS の OData クライアント ライブラリを使って、iOS プラットフォーム (iPad、iPhone など) 上に既存の OData サービスを使用するアプリケーションを構築できます。OData の iOS ライブラリには、OData サービスでメタデータから一連のプロキシ クラスを生成するコード生成ツール (odatagen) が含まれています。生成されるプロキシ クラスでは、OData の URI を生成する機能、応答をクライアント側のオブジェクトに逆シリアル化する機能、およびサービスに対して作成、読み取り、更新、および削除 (CRUD) の操作を発行する機能が提供されます。次のコード スニペットでは、顧客層ごとに OData サービスからの要求を実行する例を示しています。
// Create the client side proxy and specify the service URL.
NorthwindCatalog *proxy =
[[NorthwindCatalog alloc]initWithUri:@http://host/Northwind.svc];
// Create a query.
DataServiceQuery *query = [proxy Customers];
QueryOperationResponse *response = [query execute];
customers = [query getResults];
DataServiceQuery および QueryOperationResponse は、URI を作成し、その URI をサービスに対して実行することによってクエリを実行するのに使用します。
Windows Phone 7 ライブラリ
次は、3 つ目のプラットフォームで別の OData ライブラリの例のデモを行います。他のプラットフォームで OData を作成することについては簡単に概要を説明しましたが、ここではアプリケーションを作成するにあたって必要な手順を詳しく説明します。つまり、新しい Windows Phone 7.1 (Mango) のツールを使用して、Windows Phone 7 のデータ駆動型エクスペリエンスを作成するために必要な基本手順を紹介します。ここからは、Windows Phone 7 アプリケーションのビルド時に重要な考慮事項を説明し、OData ライブラリの使用方法を紹介します。ビルドするアプリケーションは、前の 2 つの例 (Excel 用 PowerPivot アドイン および iOS ライブラリ) で使用したのと同じ Northwind のサンプルをターゲットにします。
Windows Phone 7.1 (Mango) ベータ版ツールの最新リリースでは、OData 用 SDK サポートが大幅にアップグレードされています。新しいライブラリでは、OData 対応の Windows Phone 7 アプリケーションを簡単に作成できる一連の新機能がサポートされます。Windows Phone 7 用 Visual Studio ツールが更新され、ターゲットの OData サービスを基にしたカスタム クライアント プロキシの生成をサポートするようになりました。既存の Microsoft .NET Framework クライアントおよび Silverlight の OData クライアントに精通している方は、このことについてもご存知でしょう。Visual Studio ツールを使用して Windows Phone 7 プロジェクトでプロキシを自動生成するには、プロジェクトのツリーの [Service References] ノードを右クリックして、[サービス参照の追加] をクリックします (この操作は、Mango の新しいツールがインストールされている場合のみ可能です)。[サービス参照の追加] ダイアログ ボックスが表示されたら、対象の OData サービスの URI を入力して [移動] をクリックします。ダイアログ ボックスには、そのサービスが公開するエンティティ セットが表示されます。その後、サービスの名前空間を入力し [OK] をクリックします。[サービス参照の追加] ダイアログ ボックスを利用してコード生成を実行すると、初回は既定のオプションが使われます。しかし、ソリューション エクスプローラーの [すべてのファイルを表示] オプションをクリックすると、[サービス] の .datasvcmap ファイルを開きパラメーターを構成することで、コード生成をより細かく構成できます。図 4 は、利用できるエンティティ セットの一覧が表示された入力後の [サービス参照の追加] ダイアログ ボックスです。
図 4 [サービス参照の追加] ダイアログ ボックスの使用
Windows Phone 7 向けの Visual Studio ツールにはコマンド ライン ツールも用意されており、同じコード生成手順をコマンド ラインから実行できます。いずれの場合も、コード生成によって、サービスとのインターフェイスをとクライアント プロキシ クラス (DataServiceContext) およびサービスの構造を反映する一連のプロキシ クラスが作成されます。
LINQ のサポート
Windows Phone 7 のツールの最新バージョンにおけるクライアント LINQ サポート (.NET クライアントで現在利用できる LINQ のサポートに似ています) では、複雑な LINQ クエリを記述して、それらの LINQ クエリを URI を通じた OData サービスへの要求に変換することができます。またこのライブラリでは事前作成済みの URI を OData サービスに対して直接実行できますが、LINQ 構文を使用するとエクスペリエンスがはるかに簡潔になり、有効な OData の URI を作成する複雑さは感じられなくなります。図 5 は、LINQ のサポートを使用して Northwind データベースで在庫のあるすべての製品を照会する LINQ 式を作成する例を示しています。
図 5 LINQ クエリの実行
public void LoadData()
{
// Create a Northind Entities context and set the URL of the service.
NorthwindEntities svcContext = new NorthwindEntities(
new Uri("http://services.odata.org/Northwind/Northwind.svc")
);
// Create a DataServiceCollection to hold the results of the query.
// This collection implements INotifyCollectionChanged and can be bound in XAML.
DataServiceCollection<Product> ProductsCollection =
new DataServiceCollection<Product>( svcContext );
// Execute a LINQ query for all products with some units in stock and
// include the supplier.
var q = from p in svcContext.Products.Expand("Supplier")
where p.UnitsInStock > 0
select p;
// Asynchronously execute the query and load the results.
ProductsCollection.LoadAsync(q);
}
先ほど説明した [サービス参照の追加] ツールを使用すると、LINQ クエリの作成をサポートするクライアント プロキシ コンテキストが生成されます。
OData ライブラリには、INotifyCollectionChanged を実装する、OData 固有のコレクション型である、DataServiceCollection<T> があります。DataServiceCollection を使用してエンティティをクライアントに格納する場合、そのエンティティは XAML の UI 要素にバインドされて変更が自動的に追跡され、それら追跡対象のエンティティでのすべての更新は、クライアント コンテキストでの SaveChanges メソッドの呼び出しを経由してサービスにプッシュされます。図 6 は、DataServiceCollection クラスを使用する XAML の基本バインドをいくつか示しています ([サービス参照の追加] ツールを使用して生成されたプロキシ クラスでは、INotifyPropertyChanged が実装され、UI で行われた変更が反映されます)。
図 6 XAML バインディング
<ListBox x:Name="ProductListBox" Margin="0,0,-12,0"
ItemsSource="{Binding Products}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432" Height="78">
<TextBlock Text="{Binding ProductName}" TextWrapping="NoWrap"
Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding Supplier.CompanyName}"
TextWrapping="Wrap" Margin="12,-6,12,0"
Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
変更の追跡の手動管理を計画している場合は、コード生成時に DataServiceCollection の使用を無効にすることができます。この機能を使用しない限り通知イベントは発生しないため、これによってアプリケーションのパフォーマンスがやや向上する可能性があります。
OData サービスに対してクエリを実行するプロセスおよびその結果の具体化には、Windows Phone 7 のネットワーク スタックへの呼び出しが必要です。この呼び出しは、常に非同期呼び出しでなければなりません。DataServiceContext、BeginExecute、および EndExecute の各メソッドは、IAsyncResult パターンを使用してサービスへの要求を非同期に実行します。IAsyncResult パターンは使用が面倒な場合があるため、DataServiceCollection では LoadAsync というメソッドを用意して、非同期実行の細かい部分の大部分を隠しています。LoadAsync メソッドでは、DataServiceCollection へクエリ結果を非同期に追加し、INotifyCollectionChanged イベントを発生させて UI 自体の再設定を行います。またこのコレクション型には、サブスクライブ可能な LoadCompleted イベントも用意されており、このイベントはデータの非同期読み込みの完了時に呼び出されます。
トゥームストーン
Windows Phone 7 アプリケーションでは、別のアプリケーションをアクティブにできるように、使用中のアプリケーションを非アクティブにするよう OS から通知されることがあります。この状況は、たとえばユーザーが携帯電話のホーム ボタンを押したときや、ユーザーが着信呼び出しに応答するときに発生します。Windows Phone 7 (Mango) ベータ版リリースでは、アプリケーションの高速切り替え機能により、アクティブ状態になっているアプリケーションを非アクティブ状態にすることなく OS で別のアプリケーションに切り替えることが可能です。したがって、アプリケーションの非アクティブ化は毎回求められるわけではありません。OS からアプリケーションの非アクティブ化を求められた場合、アプリケーションで現在状態をローカルに保存するためのオプションが用意されています。したがって、再度アクティブ化された場合 (たとえば、ユーザーがその後で戻るボタンを押した場合) は、アプリケーションの以前の状態を復元し、非アクティブ化する前に行っていた作業を再開できます。この状態をトゥームストーンといいます。トゥームストーンを利用すると、アプリケーションからネットワークに接続し、帯域幅を使って外部データ ソースから再度データをダウンロードすることがなくなるため、外部データ ソースのデータを使用するアプリケーションではトゥームストーンは特に便利です。
Windows Phone 7 におけるトゥームストーンは、アプリケーションの状態をディクショナリの一連の文字列にシリアル化することで実行されます。Windows Phone 7 の OData クライアント ライブラリでは、DataServiceContext や一連の DataServiceCollections をシリアル化またはシリアル化解除できるメソッドを用意することで、現在状態のシリアル化に役立つユーティリティを提供します。これらのメソッドを使用して現在状態を表す文字列を作成する例を、図 7 のサンプル コードに示します。Windows Phone 7 アプリケーションでは、Application_Activated メソッドおよび Application_Deactivated メソッドを実装し、OS がアクティブ化や非アクティブ化のタイミングを指定できるようにする必要でがあります。DataServiceContext のシリアル化とシリアル化解除のメソッドは、これらのメソッドから使用されます。
図 7 DataServiceContext のシリアル化とシリアル化解除
// This method will serialize the local state to be stored
// when the app is deactivated.
public string Serialize()
{
var saveItems = new Dictionary<string, object>();
saveItems.Add("Products", ProductsCollection);
return DataServiceState.Serialize(svcContext, saveItems);
}
// This method will deserialize the local state to be restored
// when the app is reactivated.
public void Deserialize (string state)
{
DataServiceState dsState= DataServiceState.Deserialize(state);
svcContext = dsState.Context as NorthwindEntities;
if (dsState.RootCollections.ContainsKey("Products"))
{
ProductsCollection = dsState.RootCollections["Products"] as
DataServiceCollection<Product>;
}
}
資格情報
Windows Phone 7.1 (Mango) で OData のアプリケーションを作成するにあたって最後の重要点は、OData サービスへの資格情報の指定です。多くの場合、このようなサービスにはデータを不正使用から保護する認証手法があります。Mango のツールには、クライアント ライブラリを使用して OData サービスを呼び出す際、HTTP スタックに Credentials プロパティを設定するサポートが追加されています。このプロパティは、ICredentials インターフェイスの実装を受け取り、そのインターフェイスを HTTP スタックに直接渡します。以下のコード スニペットは、DataServiceContext の作成と、ユーザー名、パスワード、およびドメイン名を使用した Credentials プロパティの設定の基本を示しています。
// This method will serialize the local state to be stored
// when the app is deactivated.
public MainViewModel()
{
// Create the data service context.
NorthwindEntities serviceContext = new NorthwindEntities(
new Uri("http://services.odata.org/Northwind/Northwind.svc"));
// Specify the basic auth credentials.
serviceContext.Credentials = new NetworkCredential(Username, Password, Domain);
}
詳細
今回は、OData、および OData に関連して構築されたエコシステム、および Windows Phone 7.1 (Mango) ベータ版の OData クライアントによる快適なモバイル アプリケーションの作成について概要を説明しました。OData の詳細については、odata.org (英語) を参照してください。WCF Data Services の詳細については、bit.ly/pX86x6、または WCF Data Services のブログ (blogs.msdn.com/astoriateam、英語) を参照してください。
Shayne Burgess はマイクロソフトのビジネス プラットフォーム部門でプログラム マネージャーを務めており、特に WCF Data Services と Open Data Protocol を担当しています。Burgess は、WCF Data Services のブログ (blogs.msdn.com/b/astoriateam、英語) に定期的に投稿しています。
この記事のレビューに協力してくれた技術スタッフの Glenn Gailey に心より感謝いたします。