こんばんわ、mvcConf @:Japan が終わって暇になった男しばやんです。なので、ちょっと Razor の内部に飛び込んでみましょうか。
とりあえずソースコードを落としてきましょう。
ASP.NET - Download: ASP.NET MVC 3 RTM
ASP.NET MVC 3 RTM と書いてありますが、ちゃんと Razor Syntax のソースコードも入ってます。展開した中に webpages というディレクトリがあるので、さらに中に入っていくと WebPages with Razor と WebMatrix で使われているアセンブリのソースコードが入ってます。
webpages ディレクトリの中には以下のアセンブリのソースが含まれています。
- Microsoft.Web.Helpers
- System.Web.Helpers
- System.Web.Razor
- System.Web.WebPages
- System.Web.WebPages.Deployment
- System.Web.WebPages.Razor
- WebMatrix
- WebMatrix.WebData
中でも一番重要なアセンブリは System.Web.Razor ですね。このアセンブリに Razor のパーサ、コードジェネレータなどが入ってます。基本的に MVC 3 で Razor が使えるようになったと言うようにしてますが、cshtml の基底クラスは WebViewPage ということはみんな知ってますよね。
え、知らなかったって?そいつはいけねぇ、今すぐ Views ディレクトリ内にある Web.config を 10 回読み直すんだ。
ほらね、いろいろ書いてあるでしょ。ちゃんと基底クラスも指定してますね。そして WebViewPage は System.Web.Mvc.dll に含まれてるんですが、WebViewPage は WebPageBase を継承してます。こいつは System.Web.WebPages に含まれてるクラスです。
ぶっちゃけ WebViewPage は MVC 用のヘルパーを初期化したりしてるだけで、ニートほどではないですが大した仕事はしてません。実際に仕事し始めるのは WebPageBase ですね。名前からわかるように WebMatrix でも使われている WebPages の基本クラスです。
ここで継承関係について見てみます。以下の内容は WebPageExecutingBase.cs から拝借しました。
/* WebPage class hierarchy WebPageExecutingBase The base class for all Plan9 files (_pagestart, _appstart, and regular pages) AppStartBase Used for _appstart.cshtml WebPageRenderingBase PageStartBase Used for _pagestart.cshtml WebPageBase WebPage Plan9Pages ViewWebPage? MVC Views */
当然ながら MVC で使うクラスは一番下です。_appstart.cshtml と _pagestart.cshtml という記述がありますが、これは基本的に WebPages で使うファイルで MVC の場合には _ViewStart.cshtml を使います。まあ機能は名前見ればすぐわかると思います。Global.asax がないのでそれの代わりに _appstart.cshtml があるといったところでしょうか。
実は WebPages アセンブリにあるクラスは cshtml ファイルのコンパイルを行いません。実はとか言っても、詳しい人なら ASP.NET は起動時にビューファイルがコンパイルされて DLL になることは知っているでしょう。WebPages はそのコンパイル結果を利用しているだけで、実際には別のクラスでコンパイルなどの起動時の処理が行われています。
とりあえず小難しい部分とかめんどくさい部分は、省略したり次回以降にするとして、今回の締めと行きましょう。今まで Razor では @ を使って書けば HTML エスケープちゃんと行われて XSS の被害減らせるよ!!(白目 とか言ってきましたね。
まあ、この説明は間違っていないんですが、Razor は単なる DSL なのでそんなエスケープする機能とか持ってません。じゃあ、だれがエスケープするの?という話ですが、WebPageExecutingBase クラスの実装を見ると一秒で理解できます。
// This method is called by generated code and needs to stay in sync with the parser public static void WriteTo(TextWriter writer, object content) { writer.Write(HttpUtility.HtmlEncode(content)); }
単純に TextWriter で出力ストリームに書き込むときに HttpUtility.HtmlEncode を挟んでるだけでした!
では次回があれば次回までさようなら!!