10月4日-5日に開催された、Developer Camp 2012 Japan Fall にて、「デバイス + クラウドで実現するこれからのサービス ~ Windows 8 + Windows Azure 編 ~」を担当させていただきました。

本エントリーは前回説明しました、「Windows ストアアプリから Windows Azure へアクセスする(その1)」の続きになります。Azure 側の環境構築と、ベースとなる Azure サービスを作成し、デプロイしてみるところまで行きましたので、今回は Windows Azure から画像と詳細情報を公開するロジックを追加して、再デプロイするところまで行きましょう。

 

  1. ASP.NET MVC アプリケーションの作成

    前回作成した PicMgr.WebApi プロジェクトにモデル クラスを追加します。
    [Models] フォルダを右クリックして [追加] – [クラス] を選択します。 
    01

    クラス名を”Picture.cs” にします。内容を以下のコードに置き換えます。
    namespace PicMgr.Models
    {
    using System.Runtime.Serialization;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System;

    [DataContract]
    public class Picture
    {

    [Key]
    public int PrimaryKey { get; set; }

    [DataMember]
    public string UniqueId { get; set; }

    [DataMember]
    public string Title { get; set; }

    [DataMember]
    public string SubTitle { get; set; }

    [DataMember]
    public string Description { get; set; }

    [DataMember]
    public string ImagePath { get; set; }

    }
    }
                     
    [参照設定] で”System.Runtime.Serialization” を追加します。
    02

    ここで一度 [Shift] + [Ctrl] + [B] キーを押してビルドしてください。
    次に、[Controllers] フォルダを右クリックして[追加] – [コントローラー] を選択します。 
    03

    コントローラー名を「PicturesController」、モデルクラスは「Picture (PicMgr.Models)」を選択、データコンテキストクラスは新規で「PicMgr.WebApi.Models.PictureContext」をデータコンテキスト型として入力し、追加ボタンを押します。
    04

    ModelsフォルダにPictureContext.csが作成されていることを確認します。
    05

    PictureContext.cs の内容は以下のようになっているはずです。
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Web;
    using System.Web.Http;
    using PicMgr.Models;
    using PicMgr.WebApi.Models;

    namespace PicMgr.WebApi.Controllers
    {
    public class PicturesController : ApiController
    {
    private PictureContext db = new PictureContext();

    // GET api/Pictures
    public IEnumerable<Picture> GetPictures()
    {
    return db.Pictures.AsEnumerable();
    }

    // GET api/Pictures/5
    public Picture GetPicture(int id)
    {
    Picture picture = db.Pictures.Find(id);
    if (picture == null)
    {
    throw new HttpResponseException(
    Request.CreateResponse(HttpStatusCode.NotFound));
    }

    return picture;
    }

    // PUT api/Pictures/5
    public HttpResponseMessage PutPicture(int id, Picture picture)
    {
    if (ModelState.IsValid && id == picture.PrimaryKey)
    {
    db.Entry(picture).State = EntityState.Modified;

    try
    {
    db.SaveChanges();
    }
    catch (DbUpdateConcurrencyException)
    {
    return Request.CreateResponse(
    HttpStatusCode.NotFound);
    }

    return Request.CreateResponse(HttpStatusCode.OK);
    }
    else
    {
    return Request.CreateResponse(
    HttpStatusCode.BadRequest);
    }
    }

    // POST api/Pictures
    public HttpResponseMessage PostPicture(Picture picture)
    {
    if (ModelState.IsValid)
    {
    db.Pictures.Add(picture);
    db.SaveChanges();

    HttpResponseMessage response =
    Request.CreateResponse(HttpStatusCode.Created, picture);
    response.Headers.Location =
    new Uri(Url.Link("DefaultApi", new { id = picture.PrimaryKey }));
    return response;
    }
    else
    {
    return Request.CreateResponse(
    HttpStatusCode.BadRequest);
    }
    }

    // DELETE api/Pictures/5
    public HttpResponseMessage DeletePicture(int id)
    {
    Picture picture = db.Pictures.Find(id);
    if (picture == null)
    {
    return Request.CreateResponse(
    HttpStatusCode.NotFound);
    }

    db.Pictures.Remove(picture);

    try
    {
    db.SaveChanges();
    }
    catch (DbUpdateConcurrencyException)
    {
    return Request.CreateResponse(
    HttpStatusCode.NotFound);
    }

    return Request.CreateResponse(HttpStatusCode.OK, picture);
    }

    protected override void Dispose(bool disposing)
    {
    db.Dispose();
    base.Dispose(disposing);
    }
    }
    }

  2. サンプルデータの挿入と Windows Azure SQL データベースへの移行、Web Sites へのデプロイ

    パッケージマネージャーコンソールを表示します。[ツール] - [ライブラリパッケージマネージャー] - [パッケージマネージャーコンソール] を選択します。
    06

    コンソールから次の2つのコマンドを順番に実行します:
    enable-migrations -ContextTypeName PicMgr.WebApi.Models.PictureContext
    add-migration Initial
    07

    [Migrations] フォルダがが作成されていることを確認し、”Configuration.cs” を開きます。
    08
         
    PicMgr.Models 名前空間の宣言を追加します。
    namespace PicMgr.WebApi.Migrations
    {
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Migrations;
    using System.Linq;
    using PicMgr.Models;

    ...

    Seed メソッドに以下のコードを追加して、データの挿入を行います。 (ご自分の Azure 環境でお試しになる際は、下記コード内の BLOB URL から画像を入手し、ご自分の Azure Storage BLOB へアップロードした上で URL を置き換えてください。)
    protected override void Seed(
    PicMgr.WebApi.Models.PictureContext context)
    {
    // This method will be called after migrating to the latest
    version.


    // You can use the DbSet<T>.AddOrUpdate() helper extension method
    // to avoid creating duplicate seed data. E.g.
    //
    // context.People.AddOrUpdate(
    // p => p.FullName,
    // new Person { FullName = "Andrew Peters" },
    // new Person { FullName = "Brice Lambson" },
    // new Person { FullName = "Rowan Miller" }
    // );
    //
    string dummy = "\n\nPellentesque porta, mauris quis interdum
    vehicula, urna sapien ultrices velit, nec venenatis dui odio in augue.
    Cras posuere, enim a cursus convallis, neque turpis malesuada erat,
    ut adipiscing neque tortor ac erat."
    ;

    context.Pictures.AddOrUpdate(p => p.UniqueId, new Picture
    {
    UniqueId = "1001",
    Title = "January",
    SubTitle = "January",
    Description = "お正月" + dummy,
    ImagePath =
    "http://claudiapicmgr.blob.core.windows.net/pictures/Claudia_Jan.jpg"
    });

    context.Pictures.AddOrUpdate(p => p.UniqueId, new Picture
    {
    UniqueId = "1002",
    Title = "February",
    SubTitle = "February",
    Description = "バレンタインデー" + dummy,
    ImagePath =
    "http://claudiapicmgr.blob.core.windows.net/pictures/Claudia_Feb.jpg"
    });

    context.Pictures.AddOrUpdate(p => p.UniqueId, new Picture
    {
    UniqueId = "1003",
    Title = "March",
    SubTitle = "March",
    Description = "ひな祭り" + dummy,
    ImagePath =
    "http://claudiapicmgr.blob.core.windows.net/pictures/Claudia_Mar.jpg"
    });

    context.Pictures.AddOrUpdate(p => p.UniqueId, new Picture
    {
    UniqueId = "1004",
    Title = "April",
    SubTitle = "April",
    Description = "桜吹雪" + dummy,
    ImagePath =
    "http://claudiapicmgr.blob.core.windows.net/pictures/Claudia_Apr.jpg"
    });

    context.Pictures.AddOrUpdate(p => p.UniqueId, new Picture
    {
    UniqueId = "1005",
    Title = "May",
    SubTitle = "May",
    Description = "風薫る" + dummy,
    ImagePath =
    "http://claudiapicmgr.blob.core.windows.net/pictures/Claudia_May.jpg"
    });

    context.Pictures.AddOrUpdate(p => p.UniqueId, new Picture
    {
    UniqueId = "1006",
    Title = "June",
    SubTitle = "June",
    Description = "梅雨" + dummy,
    ImagePath =
    "http://claudiapicmgr.blob.core.windows.net/pictures/Claudia_Jun.jpg"
    });

    context.SaveChanges();

    }

    パッケージマネージャーコンソールに戻り、以下のコマンドを実行します。
    update-database
    10

    ビルドします。これで Azure アプリケーションは完成です。
  3. Azure Web Sites へのデプロイと動作確認

    ソリューション エクスプローラーから [PicMgr.WebApi] プロジェクトを右クリックし、[発行…] メニューを選択します。
    11
     
    前回のエントリーと同様に「Web を発行」ダイアログが表示されますので、[設定] タブを選択します。
    [データベース] の下にある [PictureContext] にリモート接続文字列を入力します。右の[…] を選択し、こちらも前回のエントリーで作成した SQL データベースに接続するための設定情報を参考に以下のように入力します。[テスト接続] ボタンを押してデータベースに接続できることを確認し、[OK] ボタンを押します。
    12

    [この接続文字列を実行時に使用する(更新先 web.config)] 及び [Code First Migrations を実行する(アプリケーションの起動時に実行する)] をチェックし、[次へ >] ボタンを押して、[プレビュー] タブから [発行] ボタンを押します。
    13

    アプリケーションが発行されてデプロイが完了すると、前回のエントリーと同様に Web API 対応アプリのデフォルト ページが表示されます。
    14


    今度は URL の後ろに”api/pictures”を追加して、JSON データの内容を確認します。HTTP GET が PicturesController クラスの GetPictures メソッドにバインドされ、SQL データベースへアクセスし、以下のように先ほど Seed メソッドで挿入された内容が返されるはずです。
    [
    {"UniqueId":"1001","Title":"January","SubTitle":"January",
    "Description":"お正月 ...(省略)","ImagePath":
    "http://claudiapicmgr.blob.core.windows.net/pictures/Claudia_Jan.jpg"},
    ...(省略)
    {"UniqueId":"1006","Title":"June","SubTitle":"June",
    "Description":"梅雨 ...(省略)","ImagePath":
    "http://claudiapicmgr.blob.core.windows.net/pictures/Claudia_Jun.jpg"}
    ]
               
    Windows Azure Web Sites にクラウドサービス環境を作成し、アプリケーション フレームワーク技術としては ASP.NET MVC Web API、Entity Framework を活用することで、非常に簡単かつ素早く Azure 対応クラウドサービスが作成できることが実感できましたでしょうか?また、Web Sites の高速簡単デプロイ、デスクトップ上の Web サービスが何のコード変更なしに SQL データベースへの移行も含めてクラウド環境に乗っかってしまうのも、なかなか魅力的ではないかと思います。

    本エントリーではアプリケーション開発の手順を中心に説明していますが、もう少し詳しく知りたい方は英語ですが「Deploying an ASP.NET Web Application to a Windows Azure Web Site and SQL Database」 が参考になるかと思います。

    いよいよ次のエントリーでは、Windows ストアアプリからこの Web サービスへアクセスして返された JSON データをグリッドビューにバインドして表示させます。