連載:〜ScottGu氏のブログより〜“Razor”の紹介 − ASP.NET向け新ビュー・エンジンScott Guthrie 著/Chica 訳2010/07/14 |
|
|
わたしのチームが開発しているものの1つに、ASP.NET用のオプションとなる新しいビュー・エンジンがあります。
ASP.NET MVCは常に“ビュー・エンジン”という概念をサポートしてきました。これはプラグ可能なモジュールで、異なるテンプレート文法のオプションを実装します。現在のASP.NET MVCの“デフォルト”ビュー・エンジンは、ASP.NET Webフォームと同じ.aspx/.ascx/.masterファイルのテンプレートを使用します。現在使われているそのほかの人気のあるASP.NET MVCビュー・エンジンには、SparkやNHamlなどがあります。
開発中の新しいビュー・エンジン・オプションは、コードにフォーカスしたテンプレート方式を使用しており、HTML生成周りで最適化されています。この新しいビュー・エンジンのコード名は“Razor”で、まもなく最初の公開ベータ版を出荷する予定です。
設計目標
いくつかの設計目標があったので、“Razor”をプロトタイプ化し評価しました。
コンパクトさ、表現的、流動的:Razorはファイルに必要な文字やキーストロークの数を最小化し、高速で流動的なコーディング・ワークフローを可能にします。多くのテンプレートの文法とは違い、HTML内で明示的にサーバ・ブロックを示すためのコーディングが必要ありません。パーサーはこれをコードから推測できるようになっています。このために、非常にコンパクトで表現的な文法が可能になり、クリーンで、素早く、楽しくタイプできます。
簡単に習得:Razorは簡単に習得できるので、最小限の概念で素早く実用的になります。使用するのはすべて既存の言語やHTMLのスキルです。
新しい言語ではありません:Razorでは意識的に新しい命令言語を作成しないようにしました。その代わり、開発者が既存のC#/VB(またはそのほかの)言語スキルをRazorで使用できるようにし、選択した言語で素晴らしいHTML構築のワークフローを可能にするテンプレート・タグの文法を提供するようにしました。
テキスト・エディタでの作業:Razorでは特別なツールは必要なく、プレーンで昔ながらのテキスト・エディタでも生産的に使えます(メモ帳アプリでもしっかりと動きます)。
優れたIntelliSenseを完備:Razorは特別なツールやコード・エディタを必要としない設計になっていますが、Visual Studioでは素晴らしいステートメント補完のサポートがあります。Visual Studio 2010やVisual Web Developer 2010を更新して、完全なIntelliSenseが装備されるようにする予定です。
単体テストが可能:新しいビュー・エンジンの実装により、ビューの単体テストが可能になります(コントローラやWebサーバを必要とせず、すべての単体テスト・プロジェクトでホスト可能です。特別なアプリケーション・ドメインも不要です)。
最近の数カ月間は、これによりアプリケーションを構築しながら、さまざまなボランティア(.NET Web開発者ではないいくつかのグループを含む)によるユーザビリティ調査もたくさん行いました。これまでのフィードバックは非常に素晴らしいものとなっています。
選択と流動性
ASP.NETで素晴らしいものの1つは、その中のほとんどのものがプラグイン可能なことです。もし何か動作しないものがあれば、ほかのものと交換できます。
次のASP.NET MVCのリリースでは、新しく“追加->ビュー”ダイアログがあり、新しいビュー・テンプレート・ファイルを作成する際に、使用したい文法を選択することが簡単になります。一番自然なビュー方式をどれでも使用できるように、マシン上にインストールされている使用可能なビュー・エンジンを簡単に選択できるようになっています。
図1 |
RazorはASP.NET MVCにビルトインして出荷するビュー・エンジンの1つになる予定です。すべてのビュー・ヘルパー・メソッドとプログラミング・モデルの機能は、Razorと.ASPXビュー・エンジンの両方で利用可能です。
1つのアプリケーションまたはサイト内で、複数のビュー・エンジンを使用して書かれたビュー・テンプレートを組み合わせることも可能です。例えば、.aspxファイル、.cshtmlまたは.vbhtmlファイル(Razorファイルのファイル拡張子で、それぞれC#およびVBのもの)、そしてSparkまたはNHamlを使用して、ビューを書けます。あるビュー・エンジンを使用するビュー・テンプレートに対して、別のビュー・エンジンで書かれた部分的なビュー・テンプレートを使用させることも可能です。
RazorでのHello Worldサンプル
Razorでは静的なHTML(またはそのほかのテキストのコンテンツ)から始めて、そこへサーバ・コードを追加することで動的なものにできます。Razorの背後にある中心的な設計目標の1つが、このコーディング・プロセスを流動的にし、最小限のキーストロークでHTMLタグにサーバ・コードを素早く統合できるようにすることです。
この簡単な例を見るために、以下のようなメッセージを出力する単純な“Hello World”のサンプルを作成してみましょう。
図2 |
■.ASPXコード・ナゲットで構築
もし上記の“Hello World”サンプルをASP.NETの既存の.ASPXタグを使用して構築した場合、HTML内で“コード・ナゲット”を示すために<%= %>ブロックを使用して書くと思います。
図3 |
この“Hello World”サンプルを作成する際に1つ確認しておくのは、一連のコードを最初と最後を示すコード・ナゲットのブロックには5文字(<%= %>)必要となることです。これらの文字のいくつか(特に%キー、たいていのキーボードで中央真ん中にあります)には、タッチタイプしにくいものもあります。
■Razor文法で構築
Razorでは@文字を使用してコード・ブロックの開始を示します。<% %>のコード・ブロックと違い、Razorはコード・ブロックを明示的に閉じる必要はありません。
図4 |
Razorのパーサーはコード・ブロック内で使用されるC#/VBコードの意味について知っているので、上記のコードを明示的に閉じる必要がありません。Razorは上記のステートメントを自己完結コード・ブロックとして認識し、暗黙にそれらを閉じてくれます。
このささいな“Hello World”の例でさえ、以前タイプしていたものより12回ものキーストロークを減らして処理できるのです。また、キーボード上では@文字は%文字よりも届きやすいため、タイピングはより素早く、より流ちょうになります。
HTML例のループとネスト
いくつかの製品(とその中の各製品価格)を一覧する場合のもう1つの簡単なシナリオを見てみましょう。
図5 |
■.ASPX コード・ナゲットで構築
もしこれをASP.NETの既存の.ASPXタグを使用して実装した場合、中の各製品に対して<li>項目を持った<ul>リストを動的に生成する以下のようなコードを書くと思います。
図6 |
■Razorで構築
以下はRazorを使用して、同等の出力を生成する方法です。
図7 |
@シンボルを使用して、どのように“foreach”ループを開始し、どのようにその中でコード・ブロックを伴ったHTMLコンテンツの行を含んでいるかを見てください。Razorのパーサーはコード・ブロックにあるC#の意味を理解できるため、<li>コンテンツがforeachに含まれており、ループすべきコンテンツとして扱われるべきであるということを決定できます。また、後ろの「}」がforeachステートメントを終了させているということも認識します。
Razorはまた、サーバ・コードとして<li>要素内の@p.Nameと@p.Priceステートメントを認識できるので、ループのたびにそれらを実行します。Razorは、どのようにHTMLとコードが一緒に使用されるかを推測することで、自動的に@p.Nameと@p.Priceコード・ブロックを閉じることができる様子を確認してください。
テンプレート内で開く/閉じるの印をたくさん追加する必要のないこのようなコードが可能であれば、、コーディングのプロセス全体は非常に流動的で素早いものになります。
Ifブロックと複数行のステートメント
以下は、そのほかの共通的なシナリオのいくつかの例です。
■Ifステートメント
上記のforeachの例のように、コード・ブロックの最初と最後を明示的にしないで、ifステートメント(もしくはそのほかのC#やVB言語構文)内にコンテンツを埋め込むことができます。例えば、以下のようになります。
図8 |
■複数行ステートメント
@{ コード } ブロックにラップすることで、コードの複数行を示せます。
図9 |
上記では、変数が複数のサーバ・コード・ブロックにあることを確認してください。例えば @{ } ブロック内で定義されている“message”変数は、@messageコード・ブロック内でも使用されています。これは概念的に.aspxタグ・ファイルの<% %>や<%= %>の文法と同じです。
■複数トークンのステートメント
@()の文法では、コード・ブロックで複数のトークンが持てます。例えば、上記のコードを書き換えて、文字列と数字を一緒に、@( コード ) ブロック内で連結できます。
図10 |
コンテンツとコードの統合
Razorのパーサーは、多くの言語的知性がビルトインされているので、明示的に自分自身で行う代わりに、面倒な処理をそれに任せられます。
■HTML内で電子メール・アドレスやそのほかの@を使用している部分を壊さないのか?
Razorの言語パーサーは、ほとんどの場合、テンプレート内の@文字がコードなのか、静的なコンテンツの中で使用されているものなのかを推論できます。例えば、以下では@文字を電子メール・アドレスの一部として使用しています。
図11 |
ファイルをパースするとき、Razorはそのコンテンツが@文字の右側かどうか確認し、それがC#コード(もしそれがCSHTMLファイルなら)、またはVBコード(もしそれがVBHTMLファイルなら)、またはただの静的コンテンツかどうかを確認しようとします。上記のコードは以下のHTMLを出力します(電子メール・アドレスが静的コンテンツとして出力され、@DateTime.Nowがコードとして評価されます)。
図12 |
コンテンツがコードとしても有効な場合(そしてそれをコンテンツとして扱いたい場合)、明示的に@文字を@@とタイプしてエスケープできます。
■ネストされたコンテンツの認識
HTMLコンテンツをif/else、foreach、そのほかのブロック・ステートメントでネスト(=入れ子に)しているときは、コンテンツ・ブロックの始まりであると正しく認識されているHTMLまたはXML要素内に、その内部コンテンツがラップされているか確認するべきです
例えば、以下は<span>要素で複数行のコンテンツ・ブロック(1つのコード・ナゲットを含む)をラップしています。
図13 |
これはクライアントに以下のコンテンツを描画します。<span>タグを含んでいることが分かります。
図14 |
ラップ・タグなしでクライアントへ描画したいコンテンツがある場合には、オプションとしてネストされたコンテンツを<text>ブロックでラップできます。
図15 |
上記のコードは以下のコンテンツを描画します。ラップするタグが何も含まれていないことが分かります。
図16 |
■HTMLエンコーディング
デフォルトで@ブロックを使用して省略されたコンテンツは、XSS攻撃シナリオからうまく防御されるように、自動的にHTMLエンコードされます。
レイアウト/マスターページのシナリオ − 基礎
Webサイト/アプリケーション内にあるすべてのページが統一された見た目と操作性を持つことは重要です。ASP.NET 2.0は“マスターページ”の概念を導入しており、.aspxベースのページやテンプレートを使用したときに、
これが有効となります。Razorでは“レイアウト・ページ”を使用して、この概念をサポートしています。これにより共通のサイト・テンプレートを定義でき、その後サイト上のすべてのビュー/ページで、そのルック&フィールを継承できます。
■簡単なレイアウトの例
以下は単純なレイアウト・ページの例です。これは、“SiteLayout.cshtml”と呼ばれるファイルに保存されます。そこには、どんな静的なHTMLコンテンツでも動的サーバ・コードでも含めることができます。そして、要求されたURLに対して特定のボディ・コンテンツを”埋め込み”たいテンプレート内の位置に“RenderBody()”ヘルパー・メソッドの呼び出しを追加します。
図17 |
これにより、要求されたページの特定のボディを構築するために必要なコンテンツ/コードだけを含む、“Home.cshtml”と呼ばれるビュー・テンプレートを作成できます。その外側のコンテンツにはレイアウト・テンプレートが利用されます。
図18 |
上記ではHome.cshtmlファイル内において、コード内で“LayoutPage”プロパティを明示的に設定しています。これはSiteLayout.cshtmlテンプレートを、このビューのテンプレートとして使用したいことを示しています。あるいは、ビュー・テンプレートとしてHome.cshtmlを起動するASP.NET MVCのコントローラ内においても、使用したいレイアウト・ファイルを示すこともできますし、サイトでデフォルト・レイアウトとして使用するように構成することでレイアウト・ファイルを示すこともできます(この場合、プロジェクト内の1つのファイルで指定すれば、すべてのビュー・テンプレートが自動的に取得します)。
Home.cshtmlをビュー・テンプレートとして描画する場合、レイアウトやサブ・ページからコンテンツを組み合わせ、クライアントへ以下のようなコンテンツを送ります。
図19 |
コンパクト、クリーン、表現的なコード
上記のコードで注目すべき1つの点は、レイアウト定義の文法と、ビュー/ページからのそれらの利用方法がクリーンで最小限であることです。上記のSiteLayout.cshtmlやHome.cshtmlファイルのスクリーンショットのコードには、その2つの.cshtmlファイルに文字通りすべてのコンテンツが含まれています。余分な構成やタグも、<%@ Page%>プレフィックスも、そのほか設定する必要のあるタグやプロパティもありません。
書かれるコードがコンパクトでシンプルで流ちょうになるように努力しています。また誰でもテキスト・エディタでそれらを開いて、編集して、簡単に修飾/カスタマイズできるようにしたいと思っています。
レイアウト/マスターページのシナリオ − オーバーライドするセクションの追加
レイアウト・ページはオプションとして、その中で異なる“セクション”を定義する機能をサポートしており、レイアウトに基づいたビュー・テンプレートをオーバーライドし、独自のコンテンツを“埋め込む”ことができます。これにより、1つのレイアウト・ページ内で不連続なコンテンツ領域であっても、簡単にオーバーライド/埋め込み可能です。
例えば、SiteLayout.cshtmlファイルに戻って、サイト内のビュー・テンプレートでオプションとして埋め込み用に選択するレイアウト内に2つのセクションを定義できます。これらのセクションを“menu”と“footer”という名前にし、RenderSection()ヘルパー呼び出しでoptional=trueというパラメータを引き渡すことでオプションである(必須でない)ことを示します(新しいC#のオプション・パラメータ文法を使用してこれを行えます。これについては以前にブログ投稿しています)。
図20 |
これら2つのセクションは“optional”としてマークされているため、Home.cshtmlファイル内でそれらを定義する必要はありません。サイトはそれらがなくても引き続きうまく動作します。
Home.cshtmlに戻って、独自のメニューとフッター・セクションを定義しましょう。以下のスクリーンショットではHome.cshtmlにコンテンツのすべてが含まれていて、それ以外は何のファイルも必要ありません。注:LayoutPageの設定をサイト全体の設定に移動させたので、もうそこには何もありません。
図21 |
独自の“menu”や“footer”セクションのオーバーライドは、ファイル内の名前付き@セクションの { } ブロックで定義されています。“main/body”コンテンツをセクションでラップせず、代わりにインラインでそれを保持するという選択をしました(どちらもキーストロークを減少させ、それらの文法を変更するのに、すべての既存ページに戻って作業する必要なく、簡単にセクションをレイアウト・ページへ追加できるようにします)。
Home.cshtmlがビュー・テンプレートとして再描画されると、そこでオーバーライドされた2つの新しい独自のセクションが統合され、レイアウトとサブ・ページからコンテンツを組み合わせ、クライアントへ次のようなコンテンツを送ります。
図22 |
HTMLヘルパーでカプセル化と再利用
レイアウト・ページを使用して、サイト全体で統一されたルック&フィールを維持する方法をカバーしました。再利用可能な”HTMLヘルパー”の作成方法も見てみましょう。これは、サイトまたは複数の異なるサイトに渡って再利用できるライブラリとして、HTML生成機能をクリーンにカプセル化できるようにします。
■コード・ベースのHTMLヘルパー
ASP.NET MVCには現在“HTMLヘルパー”の概念があり、それはコード・ブロック内で実行できるメソッドで、HTMLの生成をカプセル化します。これらは純粋なコードを使用して(通常拡張メソッドとして)実装されています。ASP.NET MVCで構築されたすべての既存のHTML拡張メソッドは(われわれが構築したものも、ほかの人が構築したものも)”Razor”のビュー・エンジンを使用して動作できます(コード変更は不要)。
図23 |
■宣言的HTMLヘルパー
コードのみのクラスを使用してHTML出力を生成するアプローチは動作しますが、理想的ではありません。
Razorで利用可能にする予定の機能の1つが、より多くの宣言的アプローチを使用して、再利用可能なHTMLヘルパーを簡単に作成する方法です。私たちの計画では、@helper{ } という宣言的文法を以下のように使用して、再利用可能なヘルパーを定義できるようにすることです。
図24 |
これらのヘルパーを含む.cshtmlファイルはViews\Helpersディレクトリに配置でき、サイトにあるどのビューやページからも、それらを再利用できます(そのほかのステップは不要)。
図25 |
上記でProductListing()ヘルパーが引数やパラメータを定義できることを確認してください。これにより、好きなパラメータを渡せるようになります(そしてオプショナル・パラメータや、Nullable型、ジェネリックなどのような既存の言語機能をすべて利用できます)。またVisual Studioの中でデバッグのサポートも得られます。
【注意】@helper文法はRazorの最初のベータ版にはありませんが、次のバージョンで有効にしようと考えているものです。コード・ベースのヘルパーは最初のベータ版で動作します。
■パラメータでインライン・テンプレートの引渡し
Razorで利用可能にする予定のもう1つの便利な(そして非常に強力な)機能は、“インライン・テンプレート”パラメータをヘルパー・メソッドへ引き渡すことができる機能です。これらの“インライン・テンプレート”はHTMLとコードの両方を含むことができ、ヘルパー・メソッドによりオンデマンドで実行できます。
以下は、クライアントへDataGridを描画する”Grid”HTMLヘルパーを使用した実際の動きの例です。
図26 |
上記のGrid.Renderメソッドの呼び出しはC#です。新しいC# 名前付きパラメータ文法を使用して、強く型付けされた引数をGrid.Renderメソッドへ引き渡しています。つまり、上記の文法の完全なステートメントの補完/IntelliSense、そしてコンパイル時チェックの恩恵を受けることができます。
列を定義する際に引き渡している“format”パラメータが“インライン・テンプレート”で、これには独自のHTMLとコードが含まれており、データ形式のカスタマイズに使用できます。これの強力なところは、Gridヘルパーがデリゲート・メソッドとしてインライン・テンプレートを起動し、そして必要なときに何度でも起動できるところです。上記のシナリオでは、グリッドの行を描画するたびに呼び出され、テンプレートが適切な応答を表示できるために使用する“item”を引き渡します。
この機能は、さらにリッチなHTMLヘルパー・メソッドを開発可能にします。(現在の拡張メソッドを構築するような)コードのアプローチでも、宣言的な @helper{ } アプローチでも、それらを実装できます。
Visual Studioのサポート
最初の方で述べたように、Razorでの目標の1つがタイピングを最小化し、基本的なテキスト・エディタ(メモ帳で十分に動作します)程度で簡単に編集できるようにすることです。それを可能にするために、その文法をクリーンで、コンパクトで、単純なものに保っています。
また、Visual Studio内でリッチなコード編集体験を得られるようにもRazorを設計しています。Razorベースのファイル内では、完全なHTML、JavaScript、C#/VBのIntelliSenseを提供します。
図27 |
上記では、foreachループ内で<li>要素内に埋め込む“@p.”コード上のProductオブジェクトに対してIntelliSenseを提供している様子をご確認ください。また、ソリューション・エクスプローラ内の¥Viewsフォルダに.aspxや.cshtmlビュー・テンプレートの両方が含まれているところもご確認ください。複数のビュー・エンジンを1つのアプリケーションで使用でき、それによりベストな文法を簡単に選択できるようになります。
まとめ
“Razor”は、コード中心のテンプレートに対して効率化された、素晴らしい新ビュー・エンジンのオプションになると考えています。高速で、表現的で、楽しいコーディング・ワークフローです。その文法はコンパクトでタイピングを減少させ、同時にタグやコード全体の可読性を改善します。次のASP.NET MVCのリリースで、ビルトインされたビュー・エンジンとして出荷する予定です。またスタンドアロンの.cshtml/.vbhtmlファイルをアプリケーションにドロップして、シングル・ページとしても起動できます。それはまた、ASP.NET Webフォーム・アプリケーション内でも利用できます。
この数カ月間に試行してくれていた開発者からのフィードバックは現在のところ非常に前向きなものです。間もなく、最初の公開ベータ版を出荷する予定で、そのフィードバックを楽しみにしています。
Hope this helps,
Scott
P.S.ブログに加え、現在Twitterを使って簡単な更新やリンク共有を行っています。twitter.com/scottguで、わたしをフォローしてください。
「〜ScottGu氏のブログより〜」 |
- 第2回 簡潔なコーディングのために (2017/7/26)
ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている - 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう - 第1回 明瞭なコーディングのために (2017/7/19)
C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える - Presentation Translator (2017/7/18)
Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
|
|