書籍転載:ASP.NET MVC 5 実践プログラミング
Razor構文
ASP.NET MVCのビュー開発では「Razor」ビューエンジンを利用するのが基本。そのRazorの基本的な文法を解説。書籍転載の3本目(導入編「4-1」)。
書籍転載について
本コーナーは、秀和システム発行の書籍『ASP.NET MVC 5 実践プログラミング』の中から、特にBuild Insiderの読者に有用だと考えられる項目を編集部が選び、同社の許可を得て転載したものです。
『ASP.NET MVC 5 実践プログラミング』の詳細や購入は秀和システムのサイトや目次ページをご覧ください。
ご注意
本記事は、書籍の内容を改変することなく、そのまま転載したものです。このため用字用語の統一ルールなどはBuild Insiderのそれとは一致しません。あらかじめご了承ください。
4-1 Razor構文
2-3節(※転載対象外)でも触れたように、ASP.NET MVCのビュー開発ではRazorを利用するのが、まず基本です。実際に利用すれば判るように、Razorはとても「賢い」ビューエンジンです。開発者の手をできるだけ煩わせないように、いたるところに配慮が行き届いていますから、正しい文法を理解しなくとも、なんとなく――直感的に書きたいことを表現できてしまうのが、Razorの良いところです。
もっとも、だからと言って、正しい文法を理解しなくて良いわけではありません。思わぬ落とし穴に陥らないためにも、Razorの基本的な解析ルールを知っておくことは、決して無駄なことではありません。
そこで本章では、まずRazorの基本的な文法について学んでいきます。導入編では漠然と触れてきたRazorの曖昧な部分を再確認し、理解を深めましょう。
4-1-1 コードナゲット(インライン式)
「@...」はRazorの最も基本的な記法で、式の値をHTMLコードに埋め込みます。コードナゲット、もしくはインライン式と呼ばれます。
<p>@Model.Title</p>
|
ASPXエンジンの<%:...%>
に相当する構文ですが、決定的に異なる点は終了のデリミター*1がないという点です。Razorでは、C#/VisualBasicの識別子、もしくは「[」(インデクサーの開始)、「.」(ドット演算子)などを正しく認識します。そして、式の一部となりえない文字を検出したところで、自動的にコードの終了と見なすのです。上の例であれば「@Model.Title」までが式で、「</p>」で式を抜けたと判断します。
- *1 プログラムコードとHTMLとの区切りを表す文字です。
その性質上、たとえば以下のような式は、Razorでは正しく認識できません。
@Model.Viewcount / 1000
|
Viewcountプロパティを1000で割った結果を求めることを期待したコードですが、結果は「36452 / 1000」(Viewcountプロパティが36452の場合)。@Model.Viewcount
の直後の空白が識別子として有効な文字ではないため、Razorはここでコードが終了したと見なすのです。結果、「/ 1000」は単なる文字列と見なされ、解析されません。
これを避けるには、「@(...)」のように式全体を丸カッコで括ります。
@(Model.Viewcount / 1000)
|
丸カッコによって式の範囲が明確になりますので、今度は期待した結果(たとえば36のような演算結果)が得られます。@(...)
を、式の範囲を明示することから、明示的コードナゲットと言います*2。
- *2 対義語として、「@...」ことを暗黙的のコードナゲットとも呼びます。
明示的コードナゲットは、曖昧なコードの区切りを明確にするためにも利用できます。たとえば、以下のようなケースです。
<a href="@Model.Key_index.html">記事目次へ</a>
|
上のコードは、本来は「<Keyプロパティ>_index.html」であることを期待したコードです。しかし、「_」がC#/Visual Basicの識別子として有効であるので、Razorは「@Model.Key_index」と見なします。結果、Key_indexプロパティが存在しないため、Razorは例外を発生するのです*3。
- *3 たまたまKey_indexプロパティが存在しても、意図しない値を出力するだけです。
このような場合にも、明示的コードナゲットを利用することで、コードの終了をRazorに通知できます。
<a href="@(Model.Key)_index.html">記事目次へ</a>
|
4-1-2 予約文字「@」のエスケープ
Razorは、実際、賢いビューエンジンで、予約文字である「@」ですらも、ほとんどの場合にはそのまま(=エスケープなど意識せずに)静的コンテンツとして表せます。たとえば以下のような文字列は、正しいRazorのコードです。
<p>admin@examples.com</p>
|
「@」の前後を見て、それが(コードナゲットではなく)静的コンテンツの一部であると判断するのです。よって、「@examples」あるいは「@examples.com」という式として処理させたい場合には、明示的コードナゲットとして「@(examples)」「@(examples.com)」のように表します。
ただし、そのような自動識別も万能ではありません。「@」が行頭、単語の区切りなどに位置する場合、Razorは「@」をコードナゲットの開始と見なすのです。
@Niftyはインターネットプロバイダーです。
|
結果、「名前 'Nifty はインターネットプロバイダーです' は現在のコンテキスト内に存在しません」のようなエラーが発生します。このような場合は、以下のように「@」をエスケープしてください。「@」をエスケープするには、「@@」のように表します。
@@Niftyはインターネットプロバイダーです。
|
【Note】「@」を識別する方法
Razorで「@」をエスケープするべきかどうか、時として、悩む場合があるかもしれません。ですが、細かなルールをあえて理解する必要はありません。というのも、Visual Studio(コードエディター)は、予約文字としての「@」を黄色くハイライトします。これによって、視覚的に「@」の状態を識別できます。
4-1-3 コードブロック
式の値を出力することを目的とした「@...」に対して、(一般的に)出力を伴わない任意の文(Statement)「@{...}」はで表現できます。ASPXエンジンでは「<%...%>」で表せる表現です。
@{
ViewBag.Title = "About";
}
|
コードブロックが表すのは文ですから、文末は(セミコロン)「;」で終わらなければならない点に注意してください。
また余談ですが、Visual Basicでコードブロックを表す場合には、「@{...}」の代わりに「@Code...End Code」を利用します。本書ではC#を対象としていますので、Visual Basicの場合の細かな構文には踏み込みませんが、Razorではその他にも、Visual BasicとC#とで構文(キーワード)が異なるものがあります。詳しくは、以下の記事なども参考にしてください。
4-1-4 制御構文(コードブロック)
if、switch、while、for/foreachなどブロックを伴う制御構文では、文の開始からブロックの終了までが、暗黙的にコードブロックと見なされます。たとえば以下は、Viewcountプロパティが10000以上の場合に[人気]アイコンを表示する例です。
@if (Model.Viewcount >= 10000) {
WriteLiteral("<strong> 人気! </strong>");
}
|
WriteLiteralは、Razorページで文字列を出力するためのメソッドです*4。ただし、このようなコードはあまりRazor的ではありません。よりRazor的には、以下のように表すのが自然です。
@if (Model.Viewcount >= 10000) {
<strong> 人気! </strong>
}
|
- *4 ASPXエンジンであれば、Response.Writeメソッドに相当します。RazorでもResponse.Writeメソッドは利用できますが、任意の位置への出力はできない=(ページの先頭で出力される)ため、現実的には利用できないと覚えておきましょう。
コードブロックでは<tag>~</tag>を検出すると、これを自動的に静的コンテンツと見なすのです。よって、WriteLiteralメソッドは必要ありません。
では、<tag>~</tag>で修飾されない、以下のようなケースではどうでしょう。
@if (Model.Viewcount >= 10000) {
人気!
}
|
この場合、「人気!」という文字列を静的コンテンツと見なせませんので、文法エラーとなります。このような文字列をブロック配下で出力するには、以下の方法があります。
(1)「@:」を付与する(単一行コンテンツ)
行頭に「@:」を付与することで、現在の行を静的コンテンツとしてRazorに通知します。
@if (Model.Viewcount >= 10000) {
@: 人気!
}
|
(2)<text>~</text>要素で括る(複数行コンテンツ)
静的コンテンツが複数行に及ぶ場合、すべての行に「@:」を付与するのは冗長です。その場合は、全体を<text>~</text>要素で括ることで、該当する範囲をすべて静的コンテンツであると見なします。
<text>は、配下の文字列が静的コンテンツであることを表すためのダミーの要素ですので、それ自体は出力されません。
@if (Model.Viewcount >= 10000) {
<text>
人気!
人気!
人気!
</text>
}
|
制御構文によるコードブロック(ステートメントブロック)は、互いに入れ子にすることもできます。Razorでは、ステートメントブロックと「@:」、<text>要素を組み合わせることで、複雑な制御ブロックもごく自然に表現できるのです。
1
3
2
1
11
12
|
<ul>
@foreach (var item in Model) {
<a href="@item.Url">
【 @item.Published.ToShortDateString()
@if (item.Published < DateTime.Now) {
@: 公開
} else {
<text> 公開予定 </text>
}
】@item.Title</a>
}
</ul>
|
- 1内側の@ifブロック
- 2アンカータグを出力
- 3外側の@foreachブロック
【Note】コードブロックでの出力
ステートメントブロックでの出力ルールは、標準のコードブロック(@{...})でも同様です。よって、以下は(あえてコードブロックで括る意味はありませんが)正しいRazorのコードです。
@{
<p> こんにちは! </p>
@: こんにちは!
<text> こんにちは! </text>
}
|
Razorでは、以下のコメントを利用できます。
(1)@*...*@
Razor標準のコメントで、@*...*@
配下のコンテンツをすべてコメントと見なします。配下に「@...」「@{...}」を含めることもできますので、特定のブロックを無効にしたい場合にも利用できます。
@*
@{
ViewBag.Title = " コメント ";
}
<h3>@ViewBag.Message</h3>
*@
|
@*...*@
は、コードブロックの配下でも利用できます。
@{
@* これはコメントです。 *@
}
|
(2)//、/* ~ */
C#標準のコメント構文で、@{...}
の配下でのみ利用できます。「//」が単一行コメント、「/*...*/」は複数行コメントです。
@{
// これはコメントです。
/*
複数行コメントはこちら
*/
}
|
(3)<!--...-->
標準的なHTMLのコメントです。RazorはあくまでHTML埋め込み型の構文を採用していますので、当然、HTMLのコメントも利用できます。ただし、(1)(2)とは異なり、ブラウザー側で処理されるコメントなので、[ソースの表示]でエンドユーザーからも見えてしまう点に注意してください。
<!--これはコメントです。-->
|
※以下では、本稿の前後を合わせて5回分(第1回~第5回)のみ表示しています。
連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。
1. ASP.NETの全体像
ASP.NET上で動作するWebアプリケーションフレームワーク「ASP.NET MVC」とは? その全体像と6つの構成要素について紹介する。書籍転載の1本目(導入編「1-1」)。
2. ASP.NET MVCとは?
なぜASP.NET MVCを使うとよいのか? Webフォームの問題点を示し、ASP.NET MVCの特徴とメリットを紹介する。書籍転載の2本目(導入編「1-2」)。
3. 【現在、表示中】≫ Razor構文
ASP.NET MVCのビュー開発では「Razor」ビューエンジンを利用するのが基本。そのRazorの基本的な文法を解説。書籍転載の3本目(導入編「4-1」)。
4. フォームを生成する - BeginFormメソッド[Razor]
<form>要素を生成するには、標準のビューヘルパーとして提供されているBeginFormメソッドが便利だ。その使い方を解説。書籍転載の4本目(基礎編「4-2-1」)。
5. ルート定義からフォームを生成する - BeginRouteFormメソッド[Razor]
ポスト先のルートパラメーターを指定した<form>要素を生成できるBeginRouteFormメソッドの使い方を解説。書籍転載の5本目(基礎編「4-2-2」)。