読者です 読者をやめる 読者になる 読者になる

しっぽを追いかけて

ぐるぐるしながら考えています

Unity と猫の話題が中心   掲載内容は個人の私見であり、所属組織の見解ではありません

ASP.NET Web API でストアアプリに DB のエンティティオブジェクトを連携する

Windows ランタイムアプリ C# JSON T4

Windows アプリで Entity Framework(以降 EF)を利用した Web API 経由で DB にアクセスする場合、マイクロソフトエバンジェリストである鈴木章太郎さんの下記のブログ記事にすでに実装方法が紹介されています

ビジネス Windows ストアアプリ開発とアーキテクチャー Part 2: REST サービスの実装

ただ、改めていろいろ試したところ、別のやり方でも EF 経由の Web API を実装できました

まずは EF6 のコードファーストによるエンティティ作成

Entity Framework のモデル用に T4 テンプレートを作る - しっぽを追いかけて の投稿で紹介した T4 テンプレートで Portable Class Library のエンティティを自動生成します

<#@ template debug="true" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".generated.cs" #>
//<auto-generated>
#region License
//-----------------------------------------------------------------------
// <copyright>
//     Copyright matatabi-ux 2014.
// </copyright>
//-----------------------------------------------------------------------
#endregion

namespace CatApp.Models
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Xml.Serialization;
    using Newtonsoft.Json;

<# 
   Generate("Cat", new Property[] {
       new Property("id", "int", "ID", "[XmlAttribute(\"id\")]", "[JsonProperty(\"id\")]"),
       new Property("name", "string", "名称", "[XmlAttribute(\"name\")]", "[JsonProperty(\"name\")]"),
       new Property("image", "string", "画像パス", "[XmlAttribute(\"image\")]", "[JsonProperty(\"image\")]"),
       new Property("description", "string", "説明", "[XmlAttribute(\"description\")]", "[JsonProperty(\"description\")]"),
   }, new NavigationProperty[] {
   }, "猫情報", "[XmlRoot(\"cat\")]");
#>
<#@ include file="../Templates/Entity.ttinclude" #>
}

次に ASP.NET Web アプリケーションの Web API のプロジェクトを追加して、EF6 と JSON.Net のライブラリを NuGet でインストール、エンティティのある Portable Class Library をプロジェクト参照します

そのあと、DbContext を継承したコンテキストクラスを Web API プロジェクトの Model フォルダあたりに追加します

public class CatContext : DbContext
{
    public CatContext() : base("Data Source=(localdb)\\v11.0;Initial Catalog=D:\\02_USERS\\DOCUMENTS\\CAT-DB.MDF;Integrated Security=True")
    {
    }

    public DbSet<Cat> Cats { get; set; }
}

基底クラスのコンストラクタ引数は SQL Server ファイルの接続先文字列です

あとは Web API プロジェクトの Controllers フォルダ配下で右クリックメニューの [追加]-[コントローラー] を選び、次のような感じでポンポンと必要事項を選択して追加ボタンを押下すると・・・

f:id:matatabi_ux:20140604002439p:plain

f:id:matatabi_ux:20140604002449p:plain

Web API の REST サービスが自動生成されました!

簡単ですね!

public class CatsController : ApiController
{
    private CatContext db = new CatContext();

    // GET: api/Cats
    public IQueryable<Cat> GetCats()
    {
        return db.Cats;
    }

    // GET: api/Cats/5
    [ResponseType(typeof(Cat))]
    public IHttpActionResult GetCat(int id)
    {
        Cat cat = db.Cats.Find(id);
        if (cat == null)
        {
            return NotFound();
        }

        return Ok(cat);
    }

    // PUT: api/Cats/5
    [ResponseType(typeof(void))]
    public IHttpActionResult PutCat(int id, Cat cat)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        if (id != cat.Id)
        {
            return BadRequest();
        }

        db.Entry(cat).State = EntityState.Modified;

        try
        {
            db.SaveChanges();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!CatExists(id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }

        return StatusCode(HttpStatusCode.NoContent);
    }

    // POST: api/Cats
    [ResponseType(typeof(Cat))]
    public IHttpActionResult PostCat(Cat cat)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        db.Cats.Add(cat);
        db.SaveChanges();

        return CreatedAtRoute("DefaultApi", new { id = cat.Id }, cat);
    }

    // DELETE: api/Cats/5
    [ResponseType(typeof(Cat))]
    public IHttpActionResult DeleteCat(int id)
    {
        Cat cat = db.Cats.Find(id);
        if (cat == null)
        {
            return NotFound();
        }

        db.Cats.Remove(cat);
        db.SaveChanges();

        return Ok(cat);
    }

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

    private bool CatExists(int id)
    {
        return db.Cats.Count(e => e.Id == id) > 0;
    }
}

試しに Windows アプリからこんなコードでアクセスして、画面に表示させてみると

/// <summary>
/// ボタンクリックイベントハンドラ
/// </summary>
/// <param name="sender">イベント発行者</param>
/// <param name="e">イベント引数</param>
public async void Button_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
    var client = new HttpClient();
    try
    {
        var response = await client.GetStringAsync(new Uri(@"http://localhost:64283/api/Cats"));
        this.ViewModel.Data = response;

    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex.ToString());
    }
}

f:id:matatabi_ux:20140604002839p:plain

無事 JSON データが取得できました