ASP.NET MVC 4(六)ヘルプ関数
56118 ワード
ヘルプ関数はいくつかのコードをカプセル化して、私たちがアプリケーションの中で再利用するのに便利で、MVC内に多くのヘルプ関数を建てて、HTMLタグを簡単に生成することができます.まず、次の例で使用するデータモデルクラス定義をリストします.
コントローラの定義:
インラインヘルプ関数
@helperタグを使用して、ビュー内のヘルプ関数を直接定義できます.
ここではインラインヘルプ関数ListArrayItemsを定義し、その後、数値内容を表示するために再利用できます.インラインヘルプ関数には戻り値がありません.ListArrayItemsを呼び出すときもパラメータにタイプCastを付けず、MVCは自動的にタイプ変換を実現します.
外部ヘルプ関数
インラインヘルプ関数は便利ですが、ビューでしか定義できません.インラインヘルプ関数が複雑であると、ビューが読みにくくなります.これに対して、外部ヘルプ関数を定義できます.外部ヘルプ関数は実際にはHtmlHelperクラスのメソッドに拡張されています.上のインラインヘルプ関数を外部ヘルプ関数に書き換えると、次のようになります.
HtmlHelperは、RouteCollection、View Bag、View Contextなどの属性を暴露し、現在のリクエストに関連するデータを取得するのに便利です.外部ヘルプ関数は、出力応答に直接書き込まれるMvcHtmlStringオブジェクトを最後に返します.このようにして、ビューでカスタム外部ヘルプ関数を使用できます.
外部ヘルプ関数を定義するネーミングスペースを導入する必要があります./Views/Webで定義することもできます.configでは、すべてのビューで使用できます.@htmlを使用して外部ヘルプ関数を呼び出します.HtmlHelperクラスのインスタンスを返します.外部ヘルプ関数を呼び出すときもパラメータタイプ変換を行います.
ヘルプ関数の文字列エンコーディング
ヘルプ関数を使用する場合は、HTML符号化の問題に注意する必要があります.まず、コントローラactionでHTMLタグ付き文字列をビューに出力する場合は、次の問題を見てみましょう.
この文字列をビューに直接出力します.
最終Razor出力の結果は次のとおりです.
の「<>」タブは、HTMLタグではなく対応する文字として符号化されています.これは、安全上の理由から、HTMLタグやJavascriptスクリプトの動的埋め込みを防止します.ヘルプ関数からHTMLタグを出力するとしたらどのような結果になるのでしょうか?次の例を見てください.
ビューファイルでこのヘルプ関数を呼び出してHTMLタグを出力します.
今回得られたのがHTMLの編集ボックスです.これは、私たちのHTMLヘルプ関数が返すMvcHtmlStringが安全と信頼され、出力の結果をHTML符号化しないためです.ヘルプ関数がMvcHtmlStringではなく、通常のStringを返します.たとえば、次のようになります.
このとき文字列はHTMLで符号化され、inputタグは出力されません.しかし、このような結果は
htmlを使います.Encode()はダイナミックコンテンツを符号化し、結果としてMvcHtmlStringオブジェクトを返します.これにより、ダイナミックコンテンツの埋め込みによるセキュリティ・ホールが回避され、本当に表示するHTMLタグが正しくレンダリングされます.
組み込まれたFormヘルプ関数
HTMLのFormタグを使用して、コミットするデータを編集するフォームを直接作成できます.
このような問題は、フォームがコミットしたURLをハードコーディングする必要があることです.実際には、組み込まれたBeginFormヘルプ関数を使用してフォームを作成することができます.
BeginFormはフォームを開始し、EndFormはフォームを終了します.実際にはRazorコードブロックを使用するのが一般的です.
@usingは、EndFormを呼び出す必要がなくなり、自己閉じたフォームを作成します.パラメータなしのBeginFormは、現在のコントローラの現在のactionメソッドにフォームをコミットします.このほか、BeginFormには多くのリロード形式があります.次に、使用例を示します.
ここでCreatePersonはフォームをコミットするコントローラを指定し、Homeはコミットするaction、new{id="MyIdValue"}は追加のパスマッピングパラメータ、FormMethod.Post指定HTTP postメソッドを使用してデータをコミットし、new{@class=“personClass”、data_formType=“person”}でFormタグの属性を指定すると、フォームHTMLの結果は次のようになります.
また、フォームで使用するパスマッピングを指定して、コミットされたリンクを生成することもできます.たとえば、このようなパスマッピングを登録しました.
BeginRouteFormを使用してフォームを作成し、使用するパスマッピングレコードを指定します.
最後に得られた結果は、
組み込み入力ヘルプ関数
実際にはなどのHTMLタグを使用してデータの編集ボックスを作成する必要はありません.MVC組み込みでは、多くの入力ヘルプ関数が提供されています.
HTML要素
例
出力結果
Checkbox
Html.CheckBox("myCheckbox", false)
Hidden
Html.Hidden("myHidden", "val")
Radio
Html.RadioButton("myRadiobutton", "val", true)
Password
Html.Password("myPassword", "val")
Html.Password("myPassword", "val")
Text area
Html.TextArea("myTextarea", "val", 5, 20, null)
namespace HelperMethods.Models {
public partial class Person {
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
public Address HomeAddress { get; set; }
public bool IsApproved { get; set; }
public Role Role { get; set; }
}
public class Address {
public string Line1 { get; set; }
public string Line2 { get; set; }
public string City { get; set; }
[Display(Name = "ZIP CODE")]
public string PostalCode { get; set; }
public string Country { get; set; }
}
public enum Role {
Admin,
User,
Guest
}
}
コントローラの定義:
namespace HelperMethods.Controllers {
public class HomeController : Controller {
public ActionResult Index() {
ViewBag.Fruits = new string[] { "Apple", "Orange", "Pear" };
ViewBag.Cities = new string[] { "New York", "London", "Paris" };
string message = "This is an HTML element: <input>";
return View((object)message);
}
public ActionResult CreatePerson() {
return View(new Person { Role = Role.Guest});
}
[HttpPost]
public ActionResult CreatePerson(Person person) {
return View("DisplayPerson", person);
}
}
}
インラインヘルプ関数
@helperタグを使用して、ビュー内のヘルプ関数を直接定義できます.
@model string
@{
Layout = null;
}
@helper ListArrayItems(string[] items)
{
foreach (string str in items)
{
<b>@str </b>
}
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
Here are the fruits: @ListArrayItems(ViewBag.Fruits)
</div>
<div>
Here are the cities: @ListArrayItems(ViewBag.Cities)
</div>
<div>
Here is the message:
<p>@Model</p>
</div>
</body>
</html>
ここではインラインヘルプ関数ListArrayItemsを定義し、その後、数値内容を表示するために再利用できます.インラインヘルプ関数には戻り値がありません.ListArrayItemsを呼び出すときもパラメータにタイプCastを付けず、MVCは自動的にタイプ変換を実現します.
外部ヘルプ関数
インラインヘルプ関数は便利ですが、ビューでしか定義できません.インラインヘルプ関数が複雑であると、ビューが読みにくくなります.これに対して、外部ヘルプ関数を定義できます.外部ヘルプ関数は実際にはHtmlHelperクラスのメソッドに拡張されています.上のインラインヘルプ関数を外部ヘルプ関数に書き換えると、次のようになります.
namespace HelperMethods.Infrastructure {
public static class CustomHelpers {
public static MvcHtmlString ListArrayItems(this HtmlHelper html, string[] list) {
TagBuilder tag = new TagBuilder("ul");
foreach(string str in list) {
TagBuilder itemTag = new TagBuilder("li");
itemTag.SetInnerText(str);
tag.InnerHtml += itemTag.ToString();
}
return new MvcHtmlString(tag.ToString());
}
}
}
HtmlHelperは、RouteCollection、View Bag、View Contextなどの属性を暴露し、現在のリクエストに関連するデータを取得するのに便利です.外部ヘルプ関数は、出力応答に直接書き込まれるMvcHtmlStringオブジェクトを最後に返します.このようにして、ビューでカスタム外部ヘルプ関数を使用できます.
@model string
@using HelperMethods.Infrastructure
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
Here are the fruits: @Html.ListArrayItems((string[])ViewBag.Fruits) </div>
<div>
Here are the cities: @Html.ListArrayItems((string[])ViewBag.Cities) </div>
<div>
Here is the message:
<p>@Model</p>
</div>
</body>
</html>
外部ヘルプ関数を定義するネーミングスペースを導入する必要があります./Views/Webで定義することもできます.configでは、すべてのビューで使用できます.@htmlを使用して外部ヘルプ関数を呼び出します.HtmlHelperクラスのインスタンスを返します.外部ヘルプ関数を呼び出すときもパラメータタイプ変換を行います.
ヘルプ関数の文字列エンコーディング
ヘルプ関数を使用する場合は、HTML符号化の問題に注意する必要があります.まず、コントローラactionでHTMLタグ付き文字列をビューに出力する場合は、次の問題を見てみましょう.
public ActionResult Index() {
string message = "This is an HTML element: <input>";
return View((object)message);
}
この文字列をビューに直接出力します.
@model string
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>Index</title>
</head>
<body>
<p>This is the content from the view:</p>
<div>
Here is the message:
<p>@Model</p>
</div>
</body>
</html>
最終Razor出力の結果は次のとおりです.
...
<div>
Here is the message:
<p>This is an HTML element: <input></p>
</div>
...
の「<>」タブは、HTMLタグではなく対応する文字として符号化されています.これは、安全上の理由から、HTMLタグやJavascriptスクリプトの動的埋め込みを防止します.ヘルプ関数からHTMLタグを出力するとしたらどのような結果になるのでしょうか?次の例を見てください.
public static MvcHtmlString DisplayMessage(this HtmlHelper html, string msg) {
string result = String.Format("This is the message: <p>{0}</p>", msg);
return new MvcHtmlString(result);
}
ビューファイルでこのヘルプ関数を呼び出してHTMLタグを出力します.
<p>This is the content from the helper method:</p>
<div style="border: thin solid black; padding: 10px">
@Html.DisplayMessage("This is an HTML element: <input>")
</div>
今回得られたのがHTMLの編集ボックスです.これは、私たちのHTMLヘルプ関数が返すMvcHtmlStringが安全と信頼され、出力の結果をHTML符号化しないためです.ヘルプ関数がMvcHtmlStringではなく、通常のStringを返します.たとえば、次のようになります.
public staticstring DisplayMessage(this HtmlHelper html, string msg) {
return String.Format("This is the message: <p>{0}</p>","This is an HTML element: <input>"); }
このとき文字列はHTMLで符号化され、inputタグは出力されません.しかし、このような結果は
タグもHTMLで符号化され、これは私たちが望んでいる結果ではなく、正しい方法は:
public static MvcHtmlStringDisplayMessage(this HtmlHelper html) {
string encodedMessage = html.Encode("This is an HTML element: <input>");
string result = String.Format("This is the message: <p>{0}</p>", encodedMessage);
return new MvcHtmlString(result);
}
htmlを使います.Encode()はダイナミックコンテンツを符号化し、結果としてMvcHtmlStringオブジェクトを返します.これにより、ダイナミックコンテンツの埋め込みによるセキュリティ・ホールが回避され、本当に表示するHTMLタグが正しくレンダリングされます.
組み込まれたFormヘルプ関数
HTMLのFormタグを使用して、コミットするデータを編集するフォームを直接作成できます.
@model HelperMethods.Models.Person
@{
ViewBag.Title = "CreatePerson";
}
<h2>CreatePerson</h2>
<form action="/Home/CreatePerson" method="post">
<div class="dataElem">
<label>PersonId</label>
<input name="personId" value="@Model.PersonId" />
</div>
<div class="dataElem">
<label>First Name</label>
<input name="FirstName" value="@Model.FirstName" />
</div>
<div class="dataElem">
<label>Last Name</label>
<input name="lastName" value="@Model.LastName" />
</div>
<input type="submit" value="Submit" />
</form>
このような問題は、フォームがコミットしたURLをハードコーディングする必要があることです.実際には、組み込まれたBeginFormヘルプ関数を使用してフォームを作成することができます.
@Html.BeginForm()
<div class="dataElem">
<label>PersonId</label>
<input name="personId" value="@Model.PersonId" />
</div>
<div class="dataElem">
<label>First Name</label>
<input name="FirstName" value="@Model.FirstName" />
</div>
<div class="dataElem">
<label>Last Name</label>
<input name="lastName" value="@Model.LastName" />
</div>
<input type="submit" value="Submit" />
@{Html.EndForm();}
BeginFormはフォームを開始し、EndFormはフォームを終了します.実際にはRazorコードブロックを使用するのが一般的です.
@using (Html.BeginForm())
{
<div class="dataElem">
<label>PersonId</label>
<input name="personId" value="@Model.PersonId" />
</div>
<div class="dataElem">
<label>First Name</label>
<input name="FirstName" value="@Model.FirstName" />
</div>
<div class="dataElem">
<label>Last Name</label>
<input name="lastName" value="@Model.LastName" />
</div>
<input type="submit" value="Submit" />
}
@usingは、EndFormを呼び出す必要がなくなり、自己閉じたフォームを作成します.パラメータなしのBeginFormは、現在のコントローラの現在のactionメソッドにフォームをコミットします.このほか、BeginFormには多くのリロード形式があります.次に、使用例を示します.
@using (Html.BeginForm("CreatePerson", "Home",new { id = "MyIdValue" }, FormMethod.Post,new { @class = "personClass", data_formType="person"})) {
...
}
ここでCreatePersonはフォームをコミットするコントローラを指定し、Homeはコミットするaction、new{id="MyIdValue"}は追加のパスマッピングパラメータ、FormMethod.Post指定HTTP postメソッドを使用してデータをコミットし、new{@class=“personClass”、data_formType=“person”}でFormタグの属性を指定すると、フォームHTMLの結果は次のようになります.
...
<form action="/Home/CreatePerson/MyIdValue" class="personClass" data-formType="person"
method="post">
...
また、フォームで使用するパスマッピングを指定して、コミットされたリンクを生成することもできます.たとえば、このようなパスマッピングを登録しました.
routes.MapRoute( name: "FormRoute", url: "app/forms/{controller}/{action}" );
BeginRouteFormを使用してフォームを作成し、使用するパスマッピングレコードを指定します.
@using(Html.BeginRouteForm("FormRoute", new {}, FormMethod.Post, new { @class = "personClass", data_formType="person"})) {
...
}
最後に得られた結果は、
...
<form action="/app/forms/Home/CreatePerson"class="personClass" data-formType="person" method="post">
...
組み込み入力ヘルプ関数
実際にはなどのHTMLタグを使用してデータの編集ボックスを作成する必要はありません.MVC組み込みでは、多くの入力ヘルプ関数が提供されています.
HTML要素
例
出力結果
Checkbox
Html.CheckBox("myCheckbox", false)
Hidden
Html.Hidden("myHidden", "val")
Radio
Html.RadioButton("myRadiobutton", "val", true)
Password
Html.Password("myPassword", "val")
Html.Password("myPassword", "val")
Text area
Html.TextArea("myTextarea", "val", 5, 20, null)