知っている人は知っている、知らない人は知らない『NDjango』
One ASP.NET Advent Calendar 2012の16日目のエントリです。(ちょっと過ぎちゃった・・・)
ASP.NET MVCを勉強しようと思っていた矢先、Advent Calendarの募集が始まったので勢いで参加登録しました。
今は反省しています。
3日前に初めてASP.NET MVCを触りました。
僕が今、鬼気迫る表情で画面に向かっていることは容易にご想像頂けるかと思います。
さて、今日はNDjangoというオープンソースのViewエンジンを取り上げたいと思います。
DjangoというPythonのMVCフレームワークがございまして、その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#のお勉強の参考にはならないかもしれません・・・