NancyFxチュートリアル「2. プロジェクトの細かい設定をする(+ モデルを作成する)」

この記事は、Nancy Advent Calendar 2013の3日目の記事です。

前回は、プロジェクトを作成して簡単な動作確認をしました。

今回は、前回触れなかったプロジェクトの細かい設定と、ToDoアプリのモデルクラスを作っていこうと思います。

もくじ

  • 静的コンテンツを配置するディレクトリを追加する
  • すべてのViewのベースとなるViewを定義する
  • モデルを作成する

静的コンテンツを配置するディレクトリを追加する

NuGetを使いJavaScriptCSSのパッケージをインストールした際、それぞれ以下のディレクトリにインストールされます。

  • JavaScriptScriptsディレクトリ以下
  • CSSContentディレクトリ以下

これらのディレクトリに配置されますが、NancyFxではデフォルトでContentディレクトリ以下のファイルのみを静的コンテンツとして配信します。そのため、JavaScriptを配信するためには、Contentディレクトリ以下に移動するか、静的コンテンツを配信するディレクトリを追加する必要があります。

ここでは、静的コンテンツを配信するディレクトリを追加する方法について説明します。

Managing static content · NancyFx/Nancy Wiki · GitHub

NancyFxでは、フレームワークの設定を変更するためのクラスNancy.DefaultNancyBootstrapperを用意しています。このクラスを継承することで、アプリケーションの動作はもちろん、フレームワーク自身の動作もほぼ全てカスタマイズすることができます。このクラスに、静的コンテンツなどを登録できるメソッドvoid ConfigureConventions(NancyConventions)があるため、それをオーバーライドして登録します。

Bootstrapper · NancyFx/Nancy Wiki · GitHub

プロジェクトのルートに、クラスTodoApp.TodoAppBootstrapperを作成し、クラスNancy.DefaultNancyBootstrapperを継承して以下のとおり実装します。

using Nancy;
using Nancy.Conventions;

namespace TodoApp
{
    public class TodoAppBootstrapper : DefaultNancyBootstrapper
    {
        protected override void ConfigureConventions(NancyConventions nancyConventions)
        {
            base.ConfigureConventions(nancyConventions);

            // Scriptsディレクトリ以下のファイルを静的コンテンツとして扱うようにする。
            nancyConventions.StaticContentsConventions.Add(
                StaticContentConventionBuilder.AddDirectory("Scripts")    
            );
        }
    }
}

void ConfigureConventions(NancyConventions)をオーバーライドし、上記の通りScriptsディレクトリ以下のファイルを静的コンテンツとして配信するように設定しています。

この設定をすることで、Scriptsディレクトリ以下にあるJavaScriptファイルが配信されるようになりました。jQueryなどのJavaScriptファイルを参照して動作確認してみてください。

Bootstrapperクラスではこれ以外にも、アプリケーション起動時の処理を記述するメソッドvoid ApplicationStartup(TContainer, IPipelines)や、リクエスト開始時の処理を記述するメソッドvoid RequestStartup(TContainer, IPipelines, NancyContext)などがオーバーライドできます。

これらのメソッドや引数はユーザ認証の設定をする際などに登場しますので、ここでは説明を省略します。

すべてのViewのベースとなるViewを定義する

ASP.NET MVCでは、適用するレイアウトを定義する際に_ViewStart.cshtml_ViewStart.vbhtmlといったファイルを作成して指定します。この指定方法はNancyFxでも利用することができますが、少し注意が必要です。

レイアウトを指定するため、Views/_ViewStart.cshtmlファイルとViews/Shared/_Layout.cshtmlファイルを作成します。途中のSharedディレクトリも一緒に作成してください。

Views/Shared/_Layout.cshtmlには、他のテンプレートのベースとなるレイアウトを指定することができます。この詳細については、ASP.NET MVC 3の記事ですが以下のページが参考になります。

第1回 Controller−View開発のキモを押さえる − @IT

上の記事でも、レイアウトはViews/_ViewStart.cshtmlファイルで指定するとありますが、NancyFxでは指定の方法が若干異なります。

ASP.NET MVCでは、Layoutを~/Views/...のように指定しますが、NancyFxではその部分を省略して、Views以下のディレクトリから指定します。

@{
    // ASP.NET MVC は "~/Views/Shared/_Layout.cshtml" と指定する。
    Layout = "Shared/_Layout.cshtml";
}

この件については、ドキュメントを見つけられませんでした。

モデルを作成する

モデルについては、NancyFxでのサポートがありませんので、自由に選択することができます。今回はEntityFrameworkを使ってモデルファースト開発をしてみようと思います。

EntityFrameworkは、@shibayanさんのASP.NET MVC 3 開発入門を参考にしました。

ASP.NET MVC 3 開発入門 (3) - モデルをコードファーストで作成 - しばやん雑記

まずはNuGetで、EntityFramework 6 と、データベースにSQLServer CEを使うためのパッケージをインストールします。

NuGetのダイアログを開き、EntityFrameworkで検索をして以下のパッケージをインストールします。どちらも2013年12月3日時点ではバージョン6.0.1でした。

  • EntityFramework
  • EntityFramework.SqlServerCompact

f:id:rabitarochan:20131204012238p:plain

インストール後、モデルの作成に入っていきます。

Modelsディレクトリを作成し、モデルとなるクラスTodoApp.Models.TaskTodoApp.Models.Commentを追加します。クラスの定義は以下のとおりです。命名規則などは参考にした@shibayanさんの記事を参考にしてください。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace TodoApp.Models
{
    public class Task
    {
        public int TaskId { get; set; }

        [Required]
        [StringLength(128)]
        [DisplayName("タイトル")]
        public string Title { get; set; }

        [StringLength(1024)]
        [DisplayName("詳細")]
        public string Detail { get; set; }

        [DisplayName("期限日")]
        public DateTime DueDate { get; set; }

        public virtual ICollection<Comment> Comments { get; set; } 
    }
}
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace TodoApp.Models
{
    public class Comment
    {
        public int CommentId { get; set; }

        [Required]
        [DisplayName("コメント")]
        public string Message { get; set; }

        public DateTime CreatedAt { get; set; }
    }
}

モデルクラスができたので、それらを操作するためのデータコンテキストクラスTodoApp.Models.TodoAppContextと、Web.configファイルに接続文字列の設定をします。

using System.Data.Entity;

namespace TodoApp.Models
{
    public class TodoAppContext : DbContext
    {
        public DbSet<Task> Tasks { get; set; }
        public DbSet<Comment> Comments { get; set; } 
    }
}
<!-- Web.config の一部 -->
<connectionStrings>
  <add name="TodoAppContext"
       connectionString="Data Source=|DataDirectory|\TodoApp.sdf"
       providerName="System.Data.SqlServerCe.4.0" />
</connectionStrings>

さいごに、データベースの自動生成をするために、TodoAppBootstrapperクラスを修正します。

アプリケーション起動時の処理を記述するメソッドvoid ApplicationStartup(TContainer, IPipelines)をオーバーライドし、以下のように実装します。

// TodoAppBootstrapper の一部
protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines)
{
    base.ApplicationStartup(container, pipelines);

    // EntityFramework のコードファースト設定。モデルに変更がある場合にDBを作り直す。
    Database.SetInitializer(new DropCreateDatabaseIfModelChanges<TodoAppContext>());
}

これでモデルを利用するための準備が整いました。これらのクラスを利用する際は、テストなどを考慮してリポジトリパターンを利用してアクセスすることになります。リポジトリパターンについては、これも@shibayanさんのブログが参考になります。

ASP.NET MVC 3 開発入門 (4) - リポジトリパターンを適用する - しばやん雑記

まとめ

今回は、プロジェクトの細かい設定と、モデルクラスを作成しました。

プロジェクトの設定の中でも特に_ViewStart.cshtmlについては、ドキュメントや情報が少なく、間違った指定をした際のエラーがよく分からない(NullReferenceException)こともあり、つまづきやすいポイントとなっています。

次回からは、コントローラの実装に入っていきます。