NerdDinnerチュートリアルNerdDinnerステップ7:パーシャルとマスター・ページScott Guthrie 著/Chica 訳2010/02/19 |
|
|
[これは無償の"NerdDinner"アプリケーション・チュートリアルのステップ7で、ASP.NET MVCを使用して、小さいながらも完全なWebアプリケーションを構築する手順を紹介しています。]
ASP.NET MVCが採用するデザイン哲学の1つが、“Do Not Repeat Yourself”原則です(通常“DRY”といわれている)。DRYデザインはコードやロジックの重複を削除する手助けをするので、最終的にはアプリケーションを素早く構築でき、簡単に保守できるようになります。
すでにNerdDinnerのいくつかのシナリオでDRYの原則が適用されているのを見てきました。次のような例です。検証ロジックがモデル層内に実装されているため、コントローラでEditおよびCreateの両方のケースにわたって適用されます。“NotFound”ビュー・テンプレートをEdit/Details/Deleteアクション・メソッドにまたがって再利用しています。ビュー・テンプレートで規約ベースの名前付けパターンを使用しているため、Viewヘルパー・メソッドを呼び出したときに、名前を明示的に指定する必要がありません。また、EditやCreateアクションの両方のケースでDinnerFormViewModelクラスを再利用しています。
では、コードの重複を削除するためにも、ビュー・テンプレート内で“DRYの原則”が適用できる方法を見てみましょう。
EditおよびCreateビュー・テンプレートを再訪
現在、夕食会のフォームUIを表示するために2つの異なるビュー・テンプレート、“Edit.aspx”および“Create.aspx”を使用しています。簡単にそれらの外観を比較して、どれだけ似ているか明らかにしてみましょう。以下はCreateフォームの様子です。
図1 |
そして、これが“Edit”フォームの様子です。
図2 |
あまり違いはありませんね? タイトルとヘッダの文字以外、そのフォームのレイアウトや入力コントロールは同じです。
“Edit.aspx”と“Create.aspx”のビュー・テンプレートを開くと、まったく同じフォームのレイアウトと入力コントロールのコードが含まれていることが分かります。この重複は、新しい夕食会のプロパティを導入したり変更したりするときに、常に2度変更しなければならないことを意味しており、それは好ましくありません。
パーシャル・ビュー・テンプレートの使用
ASP.NET MVCは“パーシャル・ビュー”テンプレートを定義する機能をサポートしており、ページの一部分に対して、ビューの描画ロジックをカプセル化するために使用できます。“パーシャル”はビューの描画ロジックを一度定義すれば、アプリケーションにわたって複数の場所で、それを再利用できるという便利な方法を提供します。
Edit.aspxおよびCreate.aspxビュー・テンプレートの重複を“DRY化”させるのに、“DinnerForm.ascx”という名前のパーシャル・ビュー・テンプレートを作成して、両方に共通のフォーム・レイアウトや入力要素をカプセル化します。これを行うには、/Views/Dinnersディレクトリ上で右クリックして、“[Add]−[View]”メニュー・コマンドを選択します。
図3 |
これにより“Add View”ダイアログを表示します。ダイアログ内で、その新しいビューを“DinnerForm”という名前にして、“Create a pertial view(パーシャル・ビューを新規作成)”チェックボックスを選択し、DinnerFormViewModelクラスをそれに引き渡すことを示します(図4)。
図4 |
“Add”ボタンをクリックすると、Visual Studioは新しい“DinnerForm.ascx”ビュー・テンプレートを“\Views\Dinners”ディレクトリ内に作成します。
そして、Edit.aspx/Create.aspxビュー・テンプレートから、新しい“DinnerForm.ascx”パーシャル・ビュー・テンプレートに、重複するフォーム・レイアウト/入力コントロールのコードをコピー/ペーストします。
|
その後、DinnerFormパーシャル・テンプレートを呼び出し、そのフォームの重複部分を削除するように、EditおよびCreateのビュー・テンプレートを修正します。これは、ビュー・テンプレート内で、Html.RenderPartial("DinnerForm")を呼び出せば行えます。
■Create.aspx
|
■Edit.aspx
|
Html.RenderPartialメソッドを呼び出すときには、必要なパーシャル・テンプレートのパス(例えば、“~Views/Dinners/DinnerForm.ascx”)を明示的に指定できます。ところで上記のコードでは、ASP.NET MVCのコンベンション・ベースの名前付けパターンを利用しているため、描画するそのパーシャルの名前として”DinnerForm“を指定しているだけです。このようにした場合、ASP.NET MVCは最初にコンベンション・ベースのビューのディレクトリを見ます(DinnersControllerの場合、/Views/Dinnersになります)。もしそこにパーシャル・テンプレートが見つからない場合は、/Views/Sharedディレクトリを探します。
パーシャル・ビューの名前だけでHtml.RenderPartialメソッドが呼び出されたときには、ASP.NET MVCは、ビュー・テンプレートの呼び出しで使用されているのと同じModelとViewDataディクショナリ・オブジェクトをパーシャル・ビューへ引き渡します。それとは別に、別のModelオブジェクトやViewDataディクショナリをパーシャル・ビューに引き渡して利用できるようにするためのオーバーロードされたバージョンのHtml.RenderPartialメソッドもあります。これは、完全なModel/ViewModelのサブセットを引き渡したいだけの場合に便利です。
サイド・トピック:なぜ<%= %>の代わりに<% %>なのか? | ||||
上記コードで気付かれたかもしれない、ささいな点ですが、Html.RenderPartialメソッドを呼び出すときに、<%= %>ブロックの代わりに<% %>ブロックを使用しています。 ASP.NETの<%= %>ブロックは、開発者が特定の値を描画することを示しています(例えば、<%= "Hello" %>は“Hello”と描画されます)。代わって、<% %>ブロックは開発者がコードを実行することを示しており、それらの中で描画される出力は、すべて明示的に行わなければなりません(例えば、<% Response.Write("Hello") %>)。 上記のHtml.RenderPartialコードと<% %>ブロックを使用している理由は、Html.RenderPartialメソッドは文字列を返さず、代わりに、呼び出しているビュー・テンプレートの出力ストリームに、直接そのコンテンツを出力するためです。これはパフォーマンスの効率性の理由から行っており、そうすることで、(潜在的に非常に大きい)一時的な文字列オブジェクトを作る必要がなくなります。これはメモリの使用を減少させ、アプリケーション全体の処理能力を改善します。 Html.RenderPartialメソッドを使用する場合の、よくある間違いの1つが、<% %>ブロックの中にあるために、その呼び出しの最後にセミコロンを付け忘れることです。例えば、このコードはコンパイル・エラーになります。
次のように書く必要があります。
これは、<% %>ブロックが内蔵型のコード文だからです。そして、C#コードを使用するときには、ステートメントはセミコロンで終了させる必要があります。 |
コードの明確化にパーシャル・ビュー・テンプレートを使用
“DinnerForm”パーシャル・ビュー・テンプレートを作成して、複数の場所でビューの描画ロジックが重複しないようにしました。これがパーシャル・ビュー・テンプレートを作成する最も多い理由です。
1つの場所でしか呼ばれない場合でも、パーシャル・ビューの作成が妥当である場合も、たまにあります。非常に複雑なビュー・テンプレートでは、それらのビューの描画ロジックが抽出され、1つ以上のうまく名前付けされたパーシャル・テンプレートに分割されていると、より読みやすくなる場合がよくあります。
例えば、プロジェクトにあるSite.masterファイルからの以下のコード・スニペット(まもなく取り上げます)を考えてみてください。コードは比較的簡単に読めます。これは、画面の右上にあるログイン/ログアウトのリンクを表示するロジックが“LogOnUserControl”パーシャル内でカプセル化されているというのが理由の一部です。
|
ビュー・テンプレート内のHTML/コードのタグを理解しようとして混乱したときはいつでも、その中のいくつかを抽出し、うまく名前付けしたパーシャル・ビューにリファクタリングすれば、クリアにできないかどうか検討してみてください。
マスター・ページ
パーシャル・ビューのサポートだけでなく、ASP.NET MVCは“マスター・ページ”テンプレートの作成機能もサポートしており、サイトで共有のレイアウトやトップレベルのHTMLを定義するために使用できます。そのため、コンテンツのプレースホルダ・コントロールをマスター・ページに追加でき、ビューによってオーバーライドされる、あるいは“埋めつく”される置換可能なエリアとして認識されます。これはアプリケーションにわたって共有のレイアウトを適用する、非常に効果的な(そしてDRYな)方法を提供します。
デフォルトでは、新しいASP.NET MVCプロジェクトに、自動的にマスター・ページのテンプレートが追加されます。このマスター・ページは“Site.master”という名前で、\Views\Shared\フォルダにあります。
図5 |
デフォルトのSite.masterファイルは以下のようになっています。先頭では、ナビゲーション用のメニューを持った、サイトの外側のHTMLを定義しています。それには2つの置換可能なコンテンツのプレースホルダ・コントロールがあり、1つがタイトル用で、もう1つはページの主コンテンツと置き換えられます。
|
NerdDinnerアプリケーションで作成したビュー・テンプレートのすべて(“List”、“Details”、“Edit”、“Create”、“NotFound”など)が、このSite.masterテンプレートに基づいています。これは、“Add View”ダイアログを使用してビューを作成したときに、先頭にある<% @ Page %>ディレクティブへデフォルトで追加されている“MasterPageFile”属性により示されています。
|
つまりSite.masterのコンテンツを変更すれば、どのビュー・テンプレートを描画するときにも、自動的にその変更が適用されて使用されます。
Site.masterのヘッダ部分を更新して、アプリケーションのヘッダを“My MVC Application”から“NerdDinner”にしてみましょう。また、ナビゲーション・メニューも修正して、最初のタブを“Find Dinner”(HomeControllerのIndexアクション・メソッドにより処理されます)にしましょう。そして、新しい“Host Dinner”というタブを追加してみましょう(DinnersControllerのCreateアクション・メソッドにより処理されます)。
|
Site.masterファイルを保存してブラウザを更新すると、ヘッダの変更がアプリケーション内のすべてのビューにわたって表示されます。以下が例です。
図6 |
/Dinners/Edit/[id] URLの場合:
図7 |
次のステップ
パーシャルとマスター・ページは非常に柔軟性のあるオプションを提供するので、ビューをクリーンにまとめることができます。ビューのコンテンツ/コードの重複を避けることができ、ビュー・テンプレートがより読みやすく保守しやすくなるのが分かるはずです。
では、以前に構築した一覧のシナリオに戻って、スケーラブルなページングのサポートを可能にしましょう。
[注:NerdDinnerアプリケーションの完成版はhttp://nerddinner.codeplex.com/からダウンロードできます。]
「NerdDinnerチュートリアル」 |
- 第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用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
|
|