ASP.NET MVC Frameworkをさわってみる 1

最近TurboGearsをさわっていて、URLをコントローラクラスのメソッドにマップするというシンプルなアーキテクチャがすごく直感的で、すごい生産性が高くて衝撃を受けた。同じMVCパターンにしてもJavaStrutsPythonTurboGearsでここまで違うのかと、設定よりも規約を重視するという設計方針の選択がここまでの差をもたらすことに感心する。

こんなフレームワークを知ってしまったら、もはや元の方法には戻れない。今さらStrutsなんか絶対さわりたくないし*1ASP.NETにしてもURLの数だけWebフォームを作る必要があるというのも結構だるい。

そんな事を考えている内についにASP.NET MVC Frameworkのプレビュー版がリリースされた。

これはASP.NETTurboGearsやRubyOnRailsのような設定より規約を重視したMVCパターンを実現するフレームワーク。これの紹介記事が公開されてから、モジュールがリリースされるのをずっと待っていた。これを使えばまさにTurboGearsな事がASP.NETでできるようになる。

ということでさっそくダウンロードしてきて、インストールした。開発にはVisual Studio 2008かVisual Web Developer 2008 Express Edition(以降、VWD2008)が必要ということなので、VWD2008もダウンロードしてインストールした。

プロジェクトの作成

VWD2008を起動して、「ASP.NET 3.5 Extensions Web Site」プロジェクトを作成する。プロジェクト名は「AspNet」にしておく。

とりあえず、Web.configを見てみると山のように設定があったので、MVC Frameworkを使うのに必要な設定だけに変更する。

Web.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <appSettings/>
    <connectionStrings/>
    
    <system.web>
        <compilation debug="true">
            <assemblies>
                <add assembly="System.Web.Extensions, Version=3.6.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
            </assemblies>
        </compilation>
        
        <authentication mode="Windows"/>

        <httpModules>
            <add name="UrlRoutingModule" type="System.Web.Mvc.UrlRoutingModule, System.Web.Extensions, Version=3.6.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        </httpModules>
    </system.web>
    
    <system.codedom>
        <compilers>
            <compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
                <providerOption name="CompilerVersion" value="v3.5"/>
                <providerOption name="WarnAsError" value="false"/>
            </compiler>
        </compilers>
    </system.codedom>
</configuration>

必要なものは「httpModules」の「UrlRoutingModule」だけだとと思う。

次にアプリケーションファイル(Global.asax)を追加する。

Global.asax
<%@ Application Language="C#" %>
<%@ Import Namespace="System.Web.Mvc" %>

<script RunAt="server">

    void Application_Start(object sender, EventArgs e) {
        RouteTable.Routes.Add(new Route {
            Url = "[controller]/[action]/[id]",
            Defaults = new { action = "Index", id = (string)null },
            RouteHandler = typeof(MvcRouteHandler)
        });
        RouteTable.Routes.Add(new Route {
            Url = "Default.aspx",
            Defaults = new { controller = "Home", action = "Index", id = (string)null },
            RouteHandler = typeof(MvcRouteHandler)
        });
    }
       
</script>

Application_Startイベントハンドラに現段階ではよくわからないけど、おそらくURLをコントローラのメソッドにマップする設定だと思われるものを追加する。

参考↓

これで準備は完了。

コントローラ

まずはコントローラクラスを実装する。コントローラクラスは「Controllers」というフォルダにまとめておく。(強制ではない)

「App_Code/Controllers/HomeController.cs」というC#クラスファイルを追加する。

App_Code/Controllers/HomeController.cs
using System;
using System.Web.Mvc;

public class HomeController : Controller {
    [ControllerAction]
    public void Index() {
    }
}

コントローラクラスはSystem.Web.Mvc.Controllerクラスから継承する必要がある。とりあえず「Index」というpublicなメソッドを実装して、ControllerActionという属性でマークする。

ここで一回Webサイトをビルドして、「http://localhost:1032/AspNet/Home*2というURLにアクセスする。

これだけで空っぽの画面が表示される!!

これは、まず「Home」というパスが指定される事でこのURLへの要求を処理するコントローラがHomeControllerクラスだと判断される。そして、次のパスでコントローラのどのアクションを実行するかが決まるわけだが、ここでは何も指定されていないので、その場合は「Index」メソッドが規定のアクションとして呼び出されるようになっている。

そして「Index」メソッドでは何もしていないので、空っぽの画面が表示されるというわけ。

このように動作するのはアプリケーションファイルのApplication_StartイベントハンドラでRouteTableに

new Route {
    Url = "[controller]/[action]/[id]",
    Defaults = new { action = "Index", id = (string)null },
    RouteHandler = typeof(MvcRouteHandler)
}

というRouteを追加したから。

これを見てみるとURLが「[controller]/[action]/[id]」という形式になっているのがわかる。そしてDefaults(おそらく規定の設定を決めるもの)にはactionプロパティが「Index」と指定されている匿名クラスが設定されている。

この設定のおかげで先程のような動作をするのだろう。(なんという柔軟性!)

ビュー

次はこの「Index」メソッドで画面を表示してみる。画面は「Views」というフォルダにまとめておく。(こちらは強制)

「Views/Home/Home.aspx」というWebフォームを追加する。Viewsの直下に配置するのではなく、HomeControllerから利用する画面なら「Home」フォルダを作ってその中に画面を配置する必要がある。

Views/Home/Home.aspx.cs
using System;

public partial class Views_Home : System.Web.Mvc.ViewPage {
    protected void Page_Load(object sender, EventArgs e) {
    }
}

ビューとして使用するWebフォームはSystem.Web.Mvc.ViewPageクラスから継承する必要がある。

Views/Home/Home.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Home.aspx.cs" Inherits="Views_Home" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Home</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <p>Hello, World</p>
    </div>
    </form>
</body>
</html>

とりあえず文字列でも表示しとく。

あとはHomeControllerクラスのIndexメソッドでこの画面を表示するようにする。

App_Code/Controllers/HomeController.cs
[ControllerAction]
public void Index() {
    RenderView("Home");
}

「RenderView」メソッドで引数にWebフォームのファイル名を拡張子無しで指定するだけ。

これで「http://localhost:1032/AspNet/Home」にアクセスすると「Hello, World」と表示される。

これは久々に大ヒットの予感。

*1:Struts2Shaleでは変わっているのだろうか?

*2:ASP.NET開発サーバーを利用している場合