ASP.NET Core 3.0 Razor Pages 事始め(9)の続きです。
いよいよ最後となりました。
今回は公式チュートリアルのASP.NET Core Razor ページに検証を追加するに沿って進めていこうと思います。
チュートリアルの最後は、ASP.NET Core Razor ページに検証を追加します。
クライアント側の検証
Movieクラスに、検証属性を追加します。
usingSystem;usingSystem.ComponentModel.DataAnnotations;namespaceRazorPagesMovie.Models{publicclassMovie{//public string Title { get; set; }publicintID{get;set;}[StringLength(60,MinimumLength=3)][Required][Display(Name="タイトル")]publicstringTitle{get;set;}[DataType(DataType.Date)][Display(Name="リリース日")]publicDateTimeReleaseDate{get;set;}[RegularExpression(@"^[A-Z]+[a-zA-Z""'\s-]*$")][Required][Display(Name="ジャンル")]publicstringGenre{get;set;}[Range(1,10000)][Display(Name="価格")][DisplayFormat(DataFormatString="{0:#,0}",ApplyFormatInEditMode=true)]publicdecimalPrice{get;set;}[RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")][StringLength(5)][Required][Display(Name="レイティング")]publicstringRating{get;set;}}}
Required
属性は、必須項目であることを示します。
StringLength
属性は、文字列の最大長を示します。MinimumLength
を使うことで、最小長を指定することもできます。
Range
属性は、指定した範囲で値を制限します。
RegularExpression
は、ユーザが入力できる文字を正規表現で指定します。
次に、クライアント検証を有効にするために以下の記述を Create.cshtml と Edit.cshtml の最後尾に追加します。
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
ちなみに、_ValidationScriptsPartial.cshtml
は以下の通りです。
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script><script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
ビルドして、F5キーで実行してみます。
新規作成ページで、無効な値を入力してみます。無効な値を入れた場合は、他の項目に移った段階で検証が走り、エラーメッセージが表示されます。
この時、サーバーへは処理は移っていません。
ここで注目すべきは、Movieクラスで指定した検証指定が、2つのページで同じように利用されているという事です。ページごとに検証ルーチンを書く必要がないのは楽だし、統一が取れるのでとてもいいですね。
でも、メッセージが英語です(T T)
[Required(ErrorMessage="{0}は、省略することはできません")]
とか、書けばとりあえずはOKです。
だけど、すべての検証属性にこれを付けるのは、規模の大きなプログラムではあまりにも大変です。あとでやり方を調べてみます。
サーバー側の検証
クライアント検証が有効になっていないと、入力されたデータは、サーバー側で検証されるようになっています。
Create.cshtml.csのOnPostAsync
メソッドには、
publicasyncTask<IActionResult>OnPostAsync(){if(!ModelState.IsValid){returnPage();}...
という記述があります。検証エラーが発生すると、IsValidプロパティがfalseになります。
この時は、return Page();
で戻っています。
わざわざ検証用の処理を呼び出す必要はないということですね。
試しに、Create.cshtml
の
@sectionScripts{@{awaitHtml.RenderPartialAsync("_ValidationScriptsPartial");}}
を削除します。これでクライアント検証が無効になるはずです。
ビルドしなおし、ブラウザを閉じてから、再度実行してみます。
確かにサーバー側で検証が行われ、ブラウザには先ほどと同様に検証エラーが表示されます。
DataType
属性
ちなみに DataType
属性は、厳密には検証用属性ではありません。Viewに対してデータの書式設定のヒントを提供します。
例えば、
[DataType(DataType.Date)][Display(Name="リリース日")]publicDateTimeReleaseDate{get;set;}
においては、以下のようなHTMLが生成されます。
<inputclass="form-control input-validation-error"type="date"data-val="true"data-val-required="The リリース日 field is required."id="Movie_ReleaseDate"name="Movie.ReleaseDate"value=""/>
type="data"
になっている点に注目です。
この属性が無いと、
type="datetime-local"
となり、利用される入力コンポーネントが時刻も含んだものになります。
話がそれますが、日付の書式は、サーバーのCultureInfo
に基づき、既定の書式に従って表示されるようです。
@Html.DisplayForで日付を表示した場合、
1989/02/12
[DisplayFormat(DataFormatString="{0:yyyy-MM-dd}")]
と属性を追加すれば、
1989-02-12
と表示形式を変更できます。
属性は、複数の属性を纏めて1行に書くことも可能です。
以下にその例を示します。
[RegularExpression(@"^[A-Z]+[a-zA-Z""'\s-]*$"),Required,StringLength(30)]
これで、チュートリアルは終了です。公式ページのチュートリアルだけあって、RzaorPagesの基本が押さえられる内容になっていると思います。
基本は抑えられたということで、これからは、チュートリアルをやっていて、疑問に思った点やさらに詳しく知りたいと思った点を調べていこうと思います。
最後に: ASP.NET Core Razor Pagesを使った感想
ASP.NET Core Razor Pagesの説明をはじめて読んだ時には、デスクトップアプリ(Windows Forms)の開発をやっていた頃を思い出し、コードが分離されずにメンテナンスの悪い構造になってしまうのではないかと、不安を覚えました。
しかし、触ってみた感触だと、心配するようなことは無いかなというのが僕の感想です。MVCの欠点が消えて逆にいい感じです。
MVCの場合も、Modelをどうすべきかはアプリケーション設計者に任されていたわけです。
それを考えると、ViewとControllerが、Page(.cshtml)とPageModel(.cshtml.cs)に置き換わっただけです。
PageとPageModelは、常に1対1の関係ですから、コードを書いている時に、ControllerとViewとModel(ViewModel)の間をいったりきたりする必要がないので、とても快適です。
Webアプリの性質上、ページモデルに大量のメソッドを定義するようなことも無いと思います。
また、Controllerをどう分割すべきかという悩ましい問題からも解放されます。
Pagesフォルダの中に、サブフォルダを作成すれば、見通しも良くなりそうです。
僕の理解は以下のような感じです。
MVC | Razor Pages |
---|---|
View (chsthm) | Page (chsthm) |
Controller | PageModel (cshtml.cs) |
Actioneメソッド | PageModel内の Razorページハンドラー |
ViewModel | PageModel ただし完全な置き換えではない。独自にViewModelを定義するケースもあり。 |
Model | Model (多くの場合は、EFのEntityクラス) |