【T4b】モデルとビューの連携(後編)(4/6)
プロジェクトタイプ | (注意: 本文参照) |
---|---|
プロジェクト名 | T4b |
ソリューション名 | PIT4 |
注意
- 本ページの作業内容は 前のページまでの続き になっていることに注意せよ.
- 先に前のページまでをすべて読み,指示されている作業を済ませてから本ページを読むこと.
- プロジェクトの作成作業については準備作業を参照せよ.
4b-4. 属性を使った入力値の制限とチェック
次に体重や身長の入力値の範囲を制限してみよう.BMIの計算では「身長(cm)」の二乗で除する部分があるが, 仮にこの入力欄にゼロを入力されてしまうと,BMIの計算時にゼロ除算が発生してしまう. このため身長や体重に下限と上限を設けることにしよう.身長に関しては前述の通りゼロが入力できないように 下限を1にしておこう.また体重に関しても負数が入力されてしまうのは望ましくないので下限をゼロとする. 上限に関してはこの場合は必ずしも必要とはいえないが練習として設けてみることにしよう. 記録によれば身長の世界記録は272cm,体重の世界記録は 635kgとのことなので,それぞれの上限は300cm,700kgとしよう. モデルクラスに_のように追記してみよう.属性を指定するときは指定することができる値がサジェストされる. 何が指定可能なのかを知るうえで有用であるためサジェストの内容をよく見ておくとよいだろう.
|
|
ここまで入力したら実行してみよう. それぞれの入力欄に指定した範囲外の数値を指定すると _のようなメッセージが表示されるはずである.
ちなみに属性の指定順序は特に規定されていない.また_では複数の属性を各々[]
で囲って
指定しているが,[Display(Name = "体重(kg)"), Range(0, 700)]
のようにカンマ区切りで指定することも可能である.
つぎにサーバー側での入力値のチェックを実装しよう.ここまでの入力値のチェックはJavaScriptを使って, クライアント側,すなわちウェブブラウザ側で行われている.制限に引っ掛かる値が入力されている場合は 「送信」ボタンを押してもサーバ側へのPOSTリクエストが実行されることはないが,これは誤った入力内容に対する絶対的な防壁としては実は使用できない. 仮に(現在ではあまりないことだが)ウェブブラウザ側でJavaScriptが無効化されている場合は, 入力値が不正であっても送信が行われてしまう.このことを確かめてみよう.
フォームの送信を処理するためには,そのためのアクションメソッドが必要である.
今回はビュー内のフォーム( form 要素)で<form asp-for="Index">...</form>
という指定をしているので,
「送信」ボタンを押した際にはHome
コントローラーのIndex
アクションに対してPOSTリクエストが発生する.
Home
コントローラーには元から定義されている GET用のアクションメソッド は存在するが,
フォームの入力を受け付けるための POST用のアクションメソッド はまだ用意していない.まずはこれを定義しよう.
Controllers/HomeController.cs に_に示す メソッドを 追記する
(既存のIndex()
メソッドを書き換えてはならない).
|
|
強調した,POST用のIndex()
メソッドに着目する.チュートリアル【T1c】のCalcBMIメソッドと異なり,
このメソッドでは double 型のweight
,height
というような,対応するフォームのデータ項目名に合わせた引数を使っていない.
その代わり先ほどから定義しているHealthInfo
クラスの引数を使用している.
モデルバインディングを使用している場合,フォームの入力値を個別の引数として受け取る代わりに,
このように型がモデルクラスとなっている引数として受け取ることが可能である.
このアクションメソッドでは今のところは何もすることはないので,引数として渡された,すなわちフォームで送信された
モデルクラスのインスタンスをView()
メソッドに渡して,対応するビューを表示している
(11行目のView()
メソッドの呼び出し).
ここまで書けたら,どのタイミングで_に示すどちらのメソッドが動作しているのかを
検証するため,_に示す通り,_の3行目と10行目のメソッドの始まりの中カッコ{
にブレークポイント
(参考:プログラミング演習Ⅲ(2023; 金澤クラス)第02回)を設置してから実行してみよう.
すると_のようにウェブブラウザは読み込み中となり,Visual Studio を見ると_のように
GET用のIndex
アクション(引数なしのほう)が作動していることが分かるはずである.このまま Visual Studio の「続行」ボタンを
クリックすると,ウェブブラウザ側で無事にフォームが表示されるはずである.ここで_のように 入力欄にエラーにならない適当な
値を入力してから 「送信」をクリックしてみよう.すると_に示す通り,先ほどと同様に実行が一時停止し
今度はPOST用のIndex
アクション(引数ありのほう)が作動していることが分かるはずである.
このまま「続行」ボタンを押すとウェブブラウザでの表示が行われる.入力欄には先ほどの入力値が入力されたままの
状態になっているはずである.
この状態で,こんどは 入力欄を空にするかエラーとなる範囲の値を入力して 「送信」ボタンをクリックしてみよう.先ほどまでのように
エラーメッセージが表示されるはずであるが, 今度はブレークポイントに引っ掛かっていないことが分かるだろうか .
この入力チェックは前述のとおりウェブブラウザ側で行われており, エラーがある場合はそもそもサーバー側に何も送信されないようになっている .
このチェックはウェブブラウザ側で動作するプログラム(=JavaScript)を用いて実現されているため,当然のことながら
ウェブブラウザのJavaScript機能をオフにすれば機能しなくなる .ためしに以下の手順でJavaScript機能をオフにしてみよう.
ウェブブラウザのウィンドウで新しくタブを開きアドレスバーにabout:config
と入力してEnterキーを押下する(_,_).
「危険を承知の上で使用する」ボタンをクリックし,検索欄に javascript.enabled
を検索し設定値をfalse
にする(_).
この状態でフォームが表示されているタブのアドレスバーでEnterキーを押して再読み込みしてみよう.
すると,_と同様にGET用のIndex
アクション(引数なしのほう)が作動していることが分かるはずである.
このまま Visual Studio の「続行」ボタンをクリックして,今度は入力欄を空にするかエラーとなる範囲の値を入力して
「送信」ボタンを押してみよう.すると_に示す通り POST用のIndex
アクション(引数ありのほう)が作動していることが分かるはずである.
先ほど,つまりウェブブラウザのJavaScript機能が有効だった時点では,入力エラーがある状態で「送信」ボタンを押しても,
ブレークポイントに引っ掛かからない,すなわちサーバ側ではいかなる処理も実行されてはいなかった.
しかし今は JavaScript機能をオフにしたため,先ほどまで異なり入力内容にエラーがあってもサーバー側への送信が行われ,
POST用のIndex
アクションが作動した ,というわけである.
このように,フォームからサーバ側に送られてきているデータ(≒モデルクラスのインスタンス)には,常に正しい値が入力されているとは限らない,ということを覚えておこう
.つまり送られたデータは常にサーバ側でもチェックをする必要があるということである.幸い,不正な入力値が送信されたことをサーバ側,つまり
アクションメソッド内の処理で検知するための機能が ASP.NET Core には備わっている.この機能も試してみることにしよう.
プログラムをいったん終了して,POST用のIndex
アクションに_に示す内容を追記し,
また Views/Home/Index.cshtml に_に示す内容を追記しよう.
なお先ほどのブレークポイントは設置したままにしておくこと.
|
|
|
|
_の4行目ではModelState.IsValid
という bool 型のプロパティを使用している.
フォームへの入力値が正しい(≒制限に引っ掛からない)場合は,このプロパティの値は true となる.
実際のシステムなどではこのようにしてサーバ側に送られた入力内容が正しいかどうかを常にチェックするべきである.
つまり誤った入力値が送られた場合にはそれ以降の処理はキャンセルされなければならない.
本節で説明したクライアント側でのチェックやアンチフォージェリトークン(第03回参照)などによって,
あるていどは予防が可能ではあるが,「HTMLのフォーム」と「そのフォームからのPOSTを処理するプログラム」は本質的には独立したものであり
誤ったフォーマットの入力が行われる可能性は常にあると考えるべきである.
ここでは入力が正しく行われた場合にはViewData
の "result" というキーに"正しい入力 - BMI:
,
誤った入力が行われた場合には計算したBMI値
""誤った入力"
という文字列を格納して,ビュー側では_の
9~12行目でそのデータを表示している.
ここまで書けたら実行してみよう.先ほどと同様にGET用のIndex
アクションで一時停止するので
Visual Studio の「」ボタンをクリックして続行し,フォームを表示させよう.
そして 入力欄を空にするかエラーとなる範囲の値を入力して 「送信」ボタンをクリックしてみよう.
いまだウェブブラウザのJavaScript機能をオフにしたままであるので,入力に誤りがある場合であってもサーバー側への送信が行われ
POST用のIndex
アクションが作動するはずである(_).この状態で,
if文の条件文の .IsValid
の部分にマウスカーソルを重ねてみよう .すると_のように
このプロパティが false つまり入力内容に誤りがあることが検出できていることが分かるはずである.
この状態で3回ていどステップオーバー(F10キー)すると,_に示すようにif文がスキップされelse節の方が実行されることが分かるだろう.
以上を確認したら,Visual Studio の「続行」ボタンをクリックして続行する.すると
_に示すように 「投稿結果: 誤った入力
」という表示と,それから誤りのある各入力欄の隣に
「値 "" は正しくありません.
」といった表示が現れている ことが分かるはずである.
つぎに 入力欄にエラーにならない適当な値を入力してから 「送信」をクリックしてみよう(_).
ブレークポイントで停止するので,先ほど同じ要領で .IsValid
がどのように評価されているかを確認してみよう.
今回は入力内容が正しいので,_に示すように このプロパティはtrue
と評価されているはずである .
また,この状態で3回ていどステップオーバー(F10キー)すると,先ほどは異なり_に示すように
if文の内部の処理が実行されることが分かるはずである.そして,このまま「続行」ボタンをクリックして続行すると,
_に示すようにこんどは投稿結果: 正しい入力 - BMI:
という表示が現れているはずである.数値
「送信」ボタンをクリックしたときの動作をまとめておこう.
- ウェブブラウザのJavaScript機能が有効な場合:
- 入力が正しい場合:
- サーバー側へ送信が行われPOST用のアクションメソッドが動作する.
- 入力に誤りがある場合:
- サーバー側へ送信が行われない(ウェブブラウザ側でチェックが行われるため).
- 入力が正しい場合:
- ウェブブラウザのJavaScript機能が無効な場合:
- 入力が正しい場合:
- サーバー側へ送信が行われPOST用のアクションメソッドが動作する.
- 入力に誤りがある場合:
- サーバー側へ送信が行われPOST用のアクションメソッドが動作する.
- 入力が正しい場合:
またウェブブラウザにおけるJavaScript機能の有効/無効に関係なく,
- フォームへの入力内容が正しい場合:
- アクションメソッドでは
ModelState.IsValid
が true となる.
- アクションメソッドでは
- フォームへの入力内容に誤りがある場合:
- アクションメソッドでは
ModelState.IsValid
が false となる.
- アクションメソッドでは
ここまでを理解することができたら,もう一度about:config
を開きjavascript.enabled
の設定値を true に戻しておこう(_).
また先ほどのブレークポイントは解除しておこう(_).