先日、セルフホスト機能を使ってASP.NET Web APIをホストしたプロセスの公開するサービスをWindows ストア アプリから呼び出してみました。今度は、ASP.NET Web APIのOData機能を使ってODataのサービスを作ってみようと思います。
プロジェクト作成
ASP.NET MVC4のプロジェクトを作成してWebAPIを選びます。ControllersフォルダにPeopleControllerを作成して以下のコードを書きます。
namespace ODataWebAPISample.Controllers { using System.Web.Http.OData; // EntitySetController<TEntity, TKey>を継承したコントローラを作ります public class PeopleController : EntitySetController<Person, int> { } // ODataとして公開するクラス public class Person { public int Id { get; set; } public string Name { get; set; } } }
System.Web.Http.ODataという名前空間にEntitySetController
とりあえず、データの取得だけならIQueryable
namespace ODataWebAPISample.Controllers { using System.Collections.Generic; using System.Linq; using System.Web.Http.OData; // EntitySetController<TEntity, TKey>を継承したコントローラを作ります public class PeopleController : EntitySetController<Person, int> { // テスト用のデータ private static readonly ICollection<Person> People = Enumerable.Range(1, 100) .Select(i => new Person { Id = i, Name = "田中 太郎" + i }) .ToList(); // データ取得 public override IQueryable<Person> Get() { return People.AsQueryable(); } // キーを元にデータ取得 protected override Person GetEntityByKey(int key) { return People.FirstOrDefault(p => p.Id == key); } } // ODataとして公開するクラス public class Person { public int Id { get; set; } public string Name { get; set; } } }
App_StartのWebApiConfig.csで、ODataのエンドポイントを構成します。先ほど作ったPersonクラスを公開するコードは以下のようになります。
namespace ODataWebAPISample { using ODataWebAPISample.Controllers; using System.Web.Http; using System.Web.Http.OData.Builder; public static class WebApiConfig { public static void Register(HttpConfiguration config) { // ODataのエンドポイントを構成する var builder = new ODataConventionModelBuilder(); // EntityとしてPeopleを登録 builder.EntitySet<Person>("People"); // odataという名前で上で構成したODataを公開する config.Routes.MapODataRoute( "ODataDefault", "odata", builder.GetEdmModel()); // クエリの実行を許可 config.EnableQuerySupport(); } } }
ODataConventionModelBuilderを使ってれば割とよきにはからってくれるみたいです。EntitySetメソッドを呼び出してPersonクラスをPeopleという名前で登録してMapODataRouteメソッドでodataというURLでアクセスできるようにしています。
実行して動作確認
ODataの準備が出来たので実行してみます。実行したらhttp://localhost:ポート/odata/$metadataでメタデータを取得してみましょう。なんとなく、いけてそうですよね?
試しにFiddlerでhttp://localhost:5629/odata/Peopleにアクセスしてみると、以下のようなJSONが取得できます。ばっちり動いてます。
{ "odata.metadata":"http://localhost:5629/odata/$metadata#People","value":[ { "Id":1,"Name":"\u7530\u4e2d\u3000\u592a\u90ce1" },{ "Id":2,"Name":"\u7530\u4e2d\u3000\u592a\u90ce2" },{ "Id":3,"Name":"\u7530\u4e2d\u3000\u592a\u90ce3" },{ "Id":4,"Name":"\u7530\u4e2d\u3000\u592a\u90ce4" },{ ...省略... }
ODataなので例えばhttp://localhost:port/odata/People(4)みたいにピンポイントでデータをとることもOKです。
クライアントアプリ
さて、ODataで公開してると何が嬉しいってクライアントアプリでメタデータをもとにスタブを作ってくれるところです。前回Windows ストア アプリからデータ取得をやったので、今回も同じ要領でやってみようとおもいます。
Windows ストア アプリでODataを読み込むためには以下のツールをインストールしてください WCF Data Services Tools for Windows Store Apps http://www.microsoft.com/en-us/download/details.aspx?id=30714
ClientAppという名前でストアアプリを作ってサービス参照の追加を行います。
http://localhost:port/odata/$metadataを入力すると以下のように表示されると思うので名前空間を適当に入れて(ここではODataWebAPISampleにしました)追加をします。
追加すると、Service ReferencesにODataWebAPISampleが追加されます。
あとは画面に適当にGridViewを置いてODataのデータを取得して表示してみましょう。Windows ストア アプリでのODataの扱いは、この本に書いてあった気がします。(ステマ)
ちょっと色気を出してIdが偶数の人だけとってくるようにしています。
private ODataWebAPISample.Container container = new ODataWebAPISample.Container(new Uri("http://localhost:5629/odata/")); protected async override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); // IDが偶数の人のみ抽出 var query = (DataServiceQuery<Person>) this.container.People.Where(p => p.Id % 2 == 0); var task = Task.Factory.FromAsync<IEnumerable<Person>>( query.BeginExecute, query.EndExecute, null); this.gridView.ItemsSource = await task; }
なかなか、いいですな。