知っている人は知っている、知らない人は知らない『NDjango』

One ASP.NET Advent Calendar 2012の16日目のエントリです。(ちょっと過ぎちゃった・・・)


ASP.NET MVCを勉強しようと思っていた矢先、Advent Calendarの募集が始まったので勢いで参加登録しました。
今は反省しています。
3日前に初めてASP.NET MVCを触りました。
僕が今、鬼気迫る表情で画面に向かっていることは容易にご想像頂けるかと思います。


さて、今日はNDjangoというオープンソースのViewエンジンを取り上げたいと思います。
DjangoというPythonMVCフレームワークがございまして、そのViewエンジンを移植してきたものがこのNDjangoです。
ソースコードGitHubでご覧になれます。
https://github.com/Hill30/NDjango
ご覧頂くと分かる通り、F#で実装されています。アツい!*1


DjangoのViewエンジンの特徴としては、「フィルタ」「タグ」「継承」などが挙げられますが、
今日は最後の「継承」という仕組みを扱いたいと思います。
ちなみに、NDjangoはフィルタとタグを拡張できるようです。(参考)


シンプルサンプル

まずはF# + ASP.NET MVCでソリューションを作成します。
初期状態は、以下の様な構成になります。



続いて、NuGet経由でNDjangoのDLLを追加します。
AdventCalendar2012WebApp(F#)というプロジェクトの参照に追加してください。


しかし!


NDjangoはF# Power Packというライブラリに依存しています。しかも古いバージョン!
それなのに依存関係を解決してくれません。
ですので、ここでは直接NDjangoを追加するのではなく、
Nancyとかいうよく分からない(!)フレームワークを追加します。
こちらはきちんと依存関係が定義されています。

よく分からないフレームワークに助けられました。
ありがとうNancy。


今度は、Controllerに手を加えます。
HomeController.fsには既にIndexというアクションが定義されていますが、
以下の2つを新たに加えます。シンプルサンプル。

namespace FsWeb.Controllers

open System.Web
open System.Web.Mvc

[<HandleError>]
type HomeController() =
    inherit Controller()

    member this.Index  () = this.View() :> ActionResult
    member this.CSharp () = this.View() :> ActionResult
    member this.FSharp () = this.View() :> ActionResult


さて、早速Viewを追加してみましょう。
実は"NDjango Template Editor"というVSのExtensionが存在します。
これをインストールすると、以下の様なメニューが表示されるようになります。




わくわく・・・。



クリックすると、高級感あふれるウィザードが表示されます。



CSharpという名前でViewを追加してみましょう。



どきどき・・・。







ん・・・?







え・・・








うわあああぁぁぁ!!!!



ここまでのまとめ

NDjango Template Editor を使うと死ぬ(インストールしないでください)


Viewの追加

手動でCSharp.djangoというファイルを作成してください!! 手動で!!

<html>
<head>
    <meta charset="utf-8" />
</head>

<body>
	<table border=3>
		<tr>
			<th>
				<i>
					{% block author %}
					Anders Hejlsberg
					{% endblock %}
				</i>
			</th>
		</tr>
		<tr>
			<td>
				{% block logo %}
				<img src="http://bit.ly/MdkiP9" />
				{% endblock %}
			</td>
		</tr>
	</table>
</body>
</html>

blockという怪しげなキーワードが出現しましたが、これは後ほど活躍することになります。


ここまでできたら、ViewエンジンとしてNDjangoが使えるようにGlobal.fsを編集します。

namespace FsWeb

open System
open System.Web
open System.Web.Mvc
open System.Web.Routing

type Route = { controller : string
               action     : string
               id         : UrlParameter }

type Global() =
    inherit System.Web.HttpApplication()

    [<DefaultValue>]
    val mutable private templateManager : NDjango.Interfaces.ITemplateManager
    // 必須らしいのでプロパティを追加
    member this.DjangoTemplateManager
        with get ()  = this.templateManager
        and  set (x) = this.templateManager <- x

    static member RegisterRoutes (routes: RouteCollection) =
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}")
        routes.MapRoute("Default", "{controller}/{action}/{id}", 
                        {controller = "Home"; action = "Index";
                         id = UrlParameter.Optional})

    member this.Start () =
        // これも追加
        (0, NDjango.ASPMVC.DjangoViewEngine())
        |> ViewEngines.Engines.Insert

        AreaRegistration.RegisterAllAreas()
        Global.RegisterRoutes(RouteTable.Routes)


CSharp Viewの動作を確認してみます。

動きました。


さて、今度はFSharp.djangoを追加してみます。
もちろん手動で!!!
しかし今度は、先程作成したCSharp.djangoを継承する形で記述してみます。

{% extends "~\Views\Home\CSharp.django" %}

{% block author %} Don Syme {% endblock %}

{% block logo %}
<img src="http://bit.ly/TZ2prX">
{% endblock %}

blockで記述された部分を"オーバーライド"するようなイメージです。
子テンプレートは最低限の記述だけで済みます。

F#!F#!

本エントリのまとめ

Razorを使おう!

*1:それほどキレイなコードではないので、F#のお勉強の参考にはならないかもしれません・・・