5/29-30 de:code セッション SV-007 “パワフル モバイル アプリ開発 ~ 最新 Microsoft Azure Mobile Services をフル活用しよう!~ ” フォローアップ (1)

皆様、こんにちは!de:code では多くの皆様に参加いただき誠に有難うございました。セッション内でもお約束しました通り、さっそく、セッションフォローアップしていきたいと思っています。

詳細は、ビデオが出てからということになりますが、今回は概要と、ASP.NET Web API バックエンドのところの解説をしたいと思います。

全体像

image

セッションでもご紹介した通り、これがMobile Services の全体像です。クライアントはほぼすべてのクライアントに、ネイティブで対応、HTML5クライアントももちろんあります。データベースは、SQL Azure Database 以外に、Azure Table Storage、Azure Blob Storage、それにOSS で MongoDBがくわわりました。Hybrid Connections というところは、BizTalk を介して様々なデータベースが連携できます。

ASP.NET Web API バックエンド

image

これまでの Mobile Services は、Node.js バックエンドのみでしたので、クライアントで定義されたクラスから渡された JSON のデータは、そのまま、ダイナミックにスキーマが構成されて、3列あるDBであれば3列に構成されました。そのイメージはこちらです。

    1: public class Favorites
    2: {
    3:     public string Id { get; set; }
    4:  
    5:     [JsonProperty(PropertyName = "text")]
    6:     public string Text { get; set; }
    7:  
    8:     [JsonProperty(PropertyName = "userid")]
    9:     public string UserId { get; set; }
   10:  
   11:     [JsonProperty(PropertyName = "complete")]
   12:     public bool Complete { get; set; }
   13:  
   14: }

 

image

これは、SQL データベースの動的スキーマがデフォルトで ON になっているためです。

image

これに対して、新しいデータモデルでは、.NET バックエンドが採用されたため、データベースは自分で選べるようになり、またオフラインデータ対応もSQLiteを使ってできるようになりました。

image

したがって、これまでの Mobile Services は、どちらかというとデータベースはSQL固定で、クライアント側の開発者が手軽にバックエンドのNode.jsを使って開発しやすいというモデルになっていたのに対して、新しいMobile Services では、.NET バックエンドが追加されたために、自由なデータベースの選択ができるようになり、バックエンドのロジックを自分で作らなければならなくなりました。バックエンドの開発者にとっては自由度が高まったといえます。

image

また、.NET バックエンドでは、Entity Framework/CodeFirst を採用しており、最初からこれが含まれています。

したがって、いままでは、これを追加してから、ASP.NET Web API(.NETバックエンド)でコントローラーを追加してRESTでデータ公開ということが必要だったのに対して、これからは、ASP.NET Web APIバックエンドを追加してやるだけで、その中に、Entity Framework/CodeFIrst も含まれています。

ですので、using Microsoft.WindowsAzure.Mobile.Services; でこの名前空間を加えるだけで、EntityData からクラスを継承できるわけです。

Mobile Services の作成

では、ここから実際に、Visual Studio の Mobile Services テンプレートを使って、アプリを作ってみましょう。適当な名前でOKをおして保存します。

image 

Mobile Services .NET バックエンドによる CRUD 処理の実装とデバッグ

ここでは、スーパーマーケットのタイムセールのストアアプリをご紹介しました。

image

上記の手順で、クラスを作成し、DBコンテキストに DbSet を追加し、初期データを DB に挿入してみてください。クラスはこんな感じです。

    1: using Microsoft.WindowsAzure.Mobile.Service;
    2:  
    3: namespace TimeSaleAPMobileService.DataObjects
    4: {
    5:     public class ProductWithPrice : EntityData
    6:     {
    7:         public string StoreId { get; set; }
    8:         public string StoreName { get; set; }
    9:         public string PriceChangedDate { get; set; }
   10:         public string ProductName { get; set; }
   11:         public string RetailPrice { get; set; }
   12:         public string ReasonforChangePrice { get; set; }
   13:         public string PriceFixedDate { get; set; }
   14:         public string Contact { get; set; }
   15:     }
   16: }public string Text { get; set; }

そして、DBコンテキストに DbSet を追加します。

    1: public DbSet<ProductWithPrice> ProductWithPrices { get; set; }

次に、Controller を追加します。フォルダーを右クリックして、コントローラーの追加を選び、

image

テーブルコントローラーを選びます。

image

上記のように選択します。追加を行います。

次に、初期データを、WebAPIConfig の Seed メソッドの中にメンバーとして追加してやります。

    1: List<ProductWithPrice> productWithPrices = new List<ProductWithPrice>
    2:     {
    3:         new ProductWithPrice
    4:         { 
    5:             Id ="1",
    6:             StoreId = "1",
    7:             StoreName = "品川店",
    8:             PriceChangedDate = "2013/1/16 9:00",
    9:             ProductName = "白菜1個",
   10:             RetailPrice = "300",
   11:             ReasonforChangePrice = "通常価格",
   12:             PriceFixedDate = "2013/1/15 18:00",
   13:             Contact = "野菜担当 山田"
   14:         },
   15:         new ProductWithPrice
   16:         { 
   17:             Id ="2",
   18:             StoreId = "2",
   19:             StoreName = "白金高輪店",
   20:             PriceChangedDate = "2013/1/16 16:00",
   21:             ProductName = "ブドウ1房",
   22:             RetailPrice = "650",
   23:             ReasonforChangePrice = "夕方のタイムセール",
   24:             PriceFixedDate = "2013/1/16 12:00",
   25:             Contact = "店長 鈴木"
   26:         },
   27:         new ProductWithPrice
   28:         { 
   29:             Id ="3",
   30:             StoreId = "3",
   31:             StoreName = "五反田店",
   32:             PriceChangedDate = "2013/1/16 18:00",
   33:             ProductName = "トマト3個",
   34:             RetailPrice = "150",
   35:             ReasonforChangePrice = "タイムセール終了",
   36:             PriceFixedDate = "2013/1/16 12:00",
   37:             Contact = "店長 松本"
   38:         },
   39:  
   40:         new ProductWithPrice
   41:         { 
   42:             Id ="4",
   43:             StoreId = "4",
   44:             StoreName = "目黒店",
   45:             PriceChangedDate = "2013/1/17 9:00",
   46:             ProductName = "玉ねぎ3つ",
   47:             RetailPrice = "260",
   48:             ReasonforChangePrice = "木曜セール",
   49:             PriceFixedDate = "2013/1/16 18:00",
   50:             Contact = "野菜担当 山田"
   51:         },
   52:         new ProductWithPrice
   53:         {
   54:             Id ="5",
   55:             StoreId = "5",
   56:             StoreName = "渋谷店",
   57:             PriceChangedDate = "2013/1/17 9:00",
   58:             ProductName = "人参3本",
   59:             RetailPrice = "260",
   60:             ReasonforChangePrice = "木曜セール",
   61:             PriceFixedDate = "2013/1/16 18:00",
   62:             Contact = "野菜担当 青木"
   63:         },
   64:         new ProductWithPrice
   65:         {
   66:             Id ="6",
   67:             StoreId = "6",
   68:             StoreName = "川崎店",
   69:             PriceChangedDate = "2013/1/17 9:00",
   70:             ProductName = "玉ねぎ3本",
   71:             RetailPrice = "240",
   72:             ReasonforChangePrice = "タイムセール終了",
   73:             PriceFixedDate = "2013/1/16 18:00",
   74:             Contact = "野菜担当 金子"
   75:         },
   76:         new ProductWithPrice
   77:         {
   78:             Id ="7",
   79:             StoreId = "1",
   80:             StoreName = "品川店",
   81:             PriceChangedDate = "2013/1/17 9:00",
   82:             ProductName = "ながのパープル1房",
   83:             RetailPrice = "700",
   84:             ReasonforChangePrice = "タイムセール終了",
   85:             PriceFixedDate = "2013/1/16 18:00",
   86:             Contact = "野菜担当 藤田"
   87:         },
   88:         new ProductWithPrice
   89:         {
   90:             Id ="8",
   91:             StoreId = "5",
   92:             StoreName = "目黒店",
   93:             PriceChangedDate = "2013/1/17 9:00",
   94:             ProductName = "玉ねぎ3本",
   95:             RetailPrice = "240",
   96:             ReasonforChangePrice = "木曜タイムセール",
   97:             PriceFixedDate = "2013/1/16 18:00",
   98:             Contact = "野菜担当 栗田"
   99:         },
  100:     };
  101:  
  102:     foreach (ProductWithPrice productWithPrice in productWithPrices)
  103:     {
  104:         context.Set<ProductWithPrice>().Add(productWithPrice);
  105:     }
  106:  
  107:     base.Seed(context);

これで完了です。ビルドして、実行してみてください。画面右下のTry it out から実行して、GETメソッドを実行し、全初期データレコードが出てくればOKです。この時、Id列も、文字列型でいれることを忘れないでください。これは仕様ですので、いつもの癖?で整数値型等にしてしまうと、ビルドエラーも起きない代わりに、初期データが挿入されないので、もう一度やり直して実行しましょう。

image

上記の通り試します。OKであれば、プロジェクトを右クリックして、Microsoft Azure に発行しましょう。

image

この時、Debug に設定しておくと、リモートデバッグが有効になります。

image

なおプログラムの変更点は、プレビューで確認できます。OKであれば、発行をクリックして発行します。

image

image

まとめは以下の通りです。

image

 

以上です。ぜひ皆様もやってみて下さい。これだけでバックエンド作成は終了です。

ここまでのコードは、こちらにありますので、ぜひご利用ください。

次は、クライアントアプリケーションとしての Windows ストアアプリ側のコードの解説です。

鈴木 章太郎