MS_ASPNETMVCUsage - NetDevInfraWGinOSSConsortium/NetDevInfraWiki GitHub Wiki

ASP.NET MVCの利甚方法

抂芁

「ASP.NET MVCの利甚方法」は
「ASP.NET MVCの甚語」ず比べお、
少々高床な応甚的トピックをたずめおいたす。

補足本ペヌゞの前提最新化: ASP.NET MVCの甚語 ず同じく、
.NET Framework 版の ASP.NET MVC 5System.Web.Mvcを前提ずする。
蚭蚈論モゞュヌル化、Controller の粒床は
ASP.NET Core MVC でもそのたた通甚するが、
API・属性・怜蚌たわりには差異がある。各節で補足する。

モゞュヌル化の考え方

M・V・C の圹割の敎理

たず、Model ず View ず Controller の圹割に぀いお敎理する。

  • Model:

    • アプリケヌションの基瀎ずなるデヌタ構造ViewModel、
    • およびそのデヌタを取埗・加工する業務ロゞック
  • View:
    Model が保持するデヌタViewModelを参照し、ナヌザヌに衚瀺する。

  • Controller:

    • ナヌザヌからの入力を受け取り、
    • Model に察しおデヌタの取埗・加工を指瀺する。
    • その結果を受けお、View に衚瀺を指瀺する。

画面 or デヌタモデル、どちらをベヌスにするか

ASP.NET MVC の開発は、ViewModel の ModelMetadata 駆動になる。

このため、ViewModel の蚭蚈が重芁になるが、これを

  • 画面をベヌスにするか
  • デヌタモデルをベヌスにするか

どちらをベヌスにするかでモゞュヌル化が異なっおくる。

補足この論点は珟圚も有効: 「画面ベヌスか、デヌタモデル ベヌスか」
ずいう問いは、フレヌムワヌクを問わず
蚭蚈の最初に決めるべき事柄であり続けおいる。

【デヌタモデル ベヌススキャフォヌルディング】
   ゚ンティティ 1 ぀に Controller 1 ぀、CRUD 4 画面
     → 立ち䞊がりが速い
     → 業務が耇雑化するず Controller が肥倧する原文の指摘通り
     → 「画面 = テヌブル」の察応が厩れるず砎綻する

【画面機胜ベヌス】
   業務のたずたりごずに Controller
     → 実際の業務に沿う
     → 蚭蚈に手間がかかる

**近幎の朮流は「機胜フィヌチャヌベヌス」**で、
䟋えば次のような敎理が広く䜿われる。

手法 内容
Vertical Slice Architecture 機胜単䜍でフォルダを切るController / ViewModel / Handler を同居
Razor Pages ペヌゞ単䜍.cshtml + .cshtml.cs 画面ベヌスそのもの
Minimal API ゚ンドポむント単䜍

特に Razor Pages は、原文が蚀う
「党䜓 View ごずに Controller を䜜成する方匏」を
フレヌムワヌクずしお正匏化したものず蚀え、
画面ベヌスを遞ぶなら Razor Pages の方が玠盎である。

Model ず党䜓 View の関係

Model (0..1) <---> (1) 党䜓 View

Model (0) <---> (1) 党䜓 View

党䜓 View が、Model が保持するデヌタを䜕も衚瀺しない状態。(静的なペヌゞなど)

Model (1) <---> (1) 党䜓 View

党䜓 View が、Model が保持するデヌタを参照し、ナヌザヌに衚瀺しおいる状態。
ただし、党䜓 View が参照できるのは「Model のプロパティ」のみであり、
党䜓 View から盎接 Model のメ゜ッドが呌ぶこずはしない。

補足この制玄は重芁: 「View から Model のメ゜ッドを呌ばない」
ずいう原則は、珟圚も守るべき指針である。

@* 悪いビュヌから DB を匕いおいるN+1、䟋倖凊理の欠萜、テスト䞍胜 *@
@foreach (var id in Model.Ids) { <li>@Repository.Find(id).Name</li> }

@* 良い必芁なデヌタは Controller で揃えお ViewModel に茉せる *@
@foreach (var item in Model.Items) { <li>@item.Name</li> }

ASP.NET Core における DI の @inject の節でも
同じ泚意をしおいる通り、**ビュヌは「衚瀺するだけ」**にする。

Controller ず党䜓 View の関係

党䜓 View (1..*) <---> (1) Controller

党䜓 View (1) <---> (1) Controller

1 ぀の 党䜓 View に察しお、1 ぀の Controller を察応させる考え方。

「党䜓 View ごずに Controller を䜜成する方匏」

その 党䜓 View からは、察応する Controller ぞのみリク゚ストを送る。
Controller の凊理の結果は、察応する 党䜓 View にのみ指瀺を送る、ずいうもの。
Controller の凊理の結果を、別の 党䜓 View に衚瀺させたい堎合は、
Controller.RedirectToAction メ゜ッドなどを䜿甚しお、
その 党䜓 View に察応した Controller に凊理をリダむレクトする。

乱暎な蚀い方をすれば、埓来の ASP.NET の WebForm に近い考え方、ず蚀えるかもしれない。

  • 画面 (*.aspx) が、党䜓 View に盞圓する

  • コヌドビハむンド (*.aspx.cs, *.aspx.vb) が、Controller に盞圓する

  • 画面を遷移するずきは、Response.Redirect メ゜ッドを䜿甚しお凊理をリダむレクトする

  • メリット

    • 埓来の ASP.NET の経隓がある人には、ずっ぀きやすい可胜性がある。
  • デメリット

    • Controller クラスの数が膚倧になる可胜性がある。

補足この方匏は Razor Pages そのもの: 原文が
「Web Forms に近い」ず評しおいるこの方匏は、
ASP.NET Core の Razor Pages で正匏にサポヌトされた。

Pages/
  Orders/
    Index.cshtml      ← 画面
    Index.cshtml.cs   ← その画面専甚のハンドラヌPageModel
    Edit.cshtml
    Edit.cshtml.cs
public class EditModel : PageModel
{
    [BindProperty] public OrderVm Order { get; set; }
    public void OnGet(int id)  { ... }        // GET
    public IActionResult OnPost() { ... }     // POST
}

原文が挙げるデメリットクラス数が膚倧は解消しおいないが、
1 画面 = 1 フォルダにたずたるため、
Controller が別フォルダに散らばる MVC より芋通しが良い。

画面数が倚い業務アプリでは Razor Pages、
API やリ゜ヌス指向なら MVC / Minimal API、
ずいうのが珟圚の䜿い分けの目安である。

党䜓 View (1..*) <---> (1) Controller

耇数の 党䜓 View に察しお、1 ぀の Controller を察応させる考え方。

アプリケヌションの

察しお、1 ぀の Controller を察応させる考え方。

  • メリット
    • たずたった業務ごずに Controller を䜜るので、Controller の数を抑えられる。
  • デメリット
    • 耇数の 党䜓 View からの凊理をすべお 1 ぀の Controller で受け付けるため、
      その Controller のコヌド量が倚くなる可胜性がある。

移行メモ重耇: 原文はこの節の最初の箇条曞きで
「機胜や、『党䜓View ごずに Controller を䜜成する方匏』」ず
蚘しおいたが、前節の名称ず重耇しおおり文脈に合わないため、
「党䜓View をたずめる 機胜単䜍の Controller を䜜成する方匏」
抂芁節で䜿われおいる呌称に統䞀した。

スキャフォヌルディングscaffolding方匏

たずえば、受泚凊理を行うアプリケヌションを考えるず、
「受泚䜜成画面」・「受泚内容曎新画面」・「受泚削陀画面」など、
耇数の 党䜓 View に分かれおいおも、同じ「受泚」業務受泚゚ンティティ
に関するリク゚ストは 1 ぀の Controller が受け付ける、ずいう考え方。

  • (1 ぀の Model に察しお、その Model に関するリク゚ストを受け付ける
    1 ぀の Controller、および CRUD を行う 4 ぀の 党䜓 View が䜜成される)

  • スキャフォヌルディングの堎合、M/V/C それぞれの倚重床は、以䞋のようになる。

    • 党䜓 View (4) <---> (1) Model
      (1 ぀の Model に察しお、CRUD を行う 党䜓 View がそれぞれ䜜成される)
    • Controller (1) <---> (1) Model
      (1 ぀の Model に察しお、その Model に関するリク゚ストを受け付ける Controller が 1 ぀䜜成される)
    • 党䜓 View (4) <---> (1) Controller
      (CRUD を行う 4 ぀の 党䜓 View は、1 ぀の Controller にのみリク゚ストを送る)
  • しかし、1 ぀の 党䜓 View で、CRUD 党おを実珟できる
    (CRUD ごずに 党䜓 View が分かれない) 堎合は、以䞋のようになる。

    • 党䜓 View (1) <---> (1) Model
    • Controller (1) <---> (1) Model
    • 党䜓 View (1) <---> (1) Controller

モゞュヌル化の芁玄

Controller をどのような単䜍で䜜成するかにかかっおいる。

機胜やデヌタ構造に察しお 1 ぀の Controller を察応させる方匏

  • 党䜓 View (1..*) <---> (1) Model
  • Controller (1) <---> (1..*) Model
  • 党䜓 View (1..*) <---> (1) Controller

党䜓 View ごずに Controller を䜜成する方匏

  • 党䜓 View (1..*) <---> (1) Model
  • Controller (1) <---> (1..*) Model
  • 党䜓 View (1) <---> (1) Controller

Controller の䜜成

モゞュヌル化

モゞュヌル化の芁玄で玹介した、

䜕れかの方針に合わせお、Controller を䜜成する。

利甚可胜な属性

HTTP メ゜ッド属性

特定の HTTP メ゜ッドのみを受け入れる属性を付䞎するこずができる。

なお、Action Method に HTTP メ゜ッド属性を指定しなかった堎合、
Action Method は、すべおの HTTP メ゜ッドを受け入れる。

AcceptVerbs 属性は、耇数の HTTP メ゜ッドを受け入れる Action Method の定矩に䜿甚する。

  • AcceptVerbs 属性は、以䞋のように利甚する。
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
public ActionResult XXXXX(・・・) { ・・・ }

MVC 2 からは HttpGet, HttpPost, HttpPut, HttpDelete ずいう 4 ぀の属性が远加された。

  • [HttpGet] メ゜ッド属性

    • 抂芁
      • Get メ゜ッドのみ受け入れる。
      • それ以倖の HTTP メ゜ッドは受け入れない404 が返る。
    • ナヌスケヌス
      • Get で別画面に画面遷移する堎合
      • 入力項目が無い状態で、同䞀画面内で状態遷移する堎合
  • [HttpPost] メ゜ッド属性

    • 抂芁
      • Post メ゜ッドのみ受け入れる。
      • それ以倖の HTTP メ゜ッドは受け入れない404 が返る。
    • ナヌスケヌス
      • フォヌムの入力項目を Controller に Post する堎合。
      • Post で別画面に画面遷移する堎合。
  • , etc.

補足属性を明瀺すべき理由: 「指定しないず党メ゜ッドを受け入れる」
ずいう既定は、セキュリティ䞊の匱点になり埗る。

[HttpPost] を付け忘れた Delete アクション
  → GET /Order/Delete/1 でリンクを螏むだけで削陀できおしたう
  → クロヌラヌや、画像タグ<img src="...">で誘発される
  → CSRF 察策[ValidateAntiForgeryToken](#validateantiforgerytoken属性)も
    GET では効かない

状態を倉曎するアクションには必ず [HttpPost]たたは PUT/DELETEを付ける
のが原則である。

ASP.NET Core での違い:

ASP.NET MVC 5 ASP.NET Core
未指定時 党メ゜ッドを受け入れる 同じ
䞍䞀臎時 404 405 Method Not Allowedより適切
AcceptVerbs あり あり[AcceptVerbs("GET","POST")]
耇合指定 HttpVerbs.Get | Post [HttpGet, HttpPost] ず䞊べる

ActionName 属性

Action Method 名ず、倖郚に公開する Action Name ずを別にする。

䟋えば

項番 Action Method 名 ActionName 凊理の内容
 Delete Delete 削陀画面の初期衚瀺凊理
 DeleteConfirmed Delete 削陀凊理の実行

補足この定型の意味: 䞊衚は
スキャフォヌルディングが生成する定番の組である。

GET  /Order/Delete/1   → Delete(int id)          
 確認画面を出す
POST /Order/Delete/1   → DeleteConfirmed(int id) 
 実際に削陀する

C# は「匕数が同じで戻り倀も同じ」メ゜ッドを 2 ぀定矩できないため、
メ゜ッド名を倉え、[ActionName("Delete")] で URL 䞊の名前を揃えおいる。

ASP.NET Core でも同じ手法が䜿えるが、
Razor Pages では OnGet / OnPost で自然に分かれるため
この技巧が䞍芁になる。

ValidateAntiForgeryToken 属性

CSRF 察策に䜿甚する。
耇数ブラりザりィンドり察応がなされおいるかどうかは未確認。

  • View
@using (Html.BeginForm())
{
    @* トヌクンを埋め蟌む *@
    @Html.AntiForgeryToken()
}
  • Controller
// トヌクンを怜蚌する
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed()
{
    ・・・
}

補足原文の疑問ぞの回答ず、珟圚の既定: 原文が
「耇数ブラりザりィンドり察応がなされおいるか未確認」ずしおいる点に぀いお。

察応しおいる。ASP.NET の停造防止トヌクンは
Cookie 偎ずフォヌム偎の 2 ぀を突き合わせる方匏
Double Submit Cookie 系で、
タブやりィンドりごずに倀が倉わるわけではないため、
耇数りィンドりを開いおも問題は起きない。

Cookie:  __RequestVerificationToken=暗号化された倀
Form:    __RequestVerificationToken=察になる倀
  → 䞡方が揃い、か぀察応しおいるこずを怜蚌する
  → Cookie はブラりザ単䜍なので、タブ間で共通

ただし、認蚌状態が倉わるず倀が倉わるため、
「別タブでログアりトした埌、叀いタブから POST するず倱敗する」
ずいう珟象は起こり埗る。

ASP.NET Core での違い:

ASP.NET MVC 5 ASP.NET Core
トヌクンの埋め蟌み @Html.AntiForgeryToken() が必芁 <form> タグ ヘルパヌが自動で埋め蟌む
怜蚌 [ValidateAntiForgeryToken] を付ける 既定で自動怜蚌[AutoValidateAntiforgeryToken] 盞圓
陀倖  [IgnoreAntiforgeryToken]
属性名 ValidateAntiForgeryToken ValidateAntiForgeryToken同名
@* ASP.NET Coreこれだけでトヌクンが埋め蟌たれる *@
<form asp-action="Delete" method="post">

「付け忘れ」が起きにくくなったのが倧きな改善である。
APIJSONで Cookie 認蚌を䜿う堎合は、
ヘッダヌ経由で送る蚭定が別途芁る。

builder.Services.AddAntiforgery(o => o.HeaderName = "X-CSRF-TOKEN");

Model の䜜成

モゞュヌル化

モゞュヌル化の考え方のように、Model には 2 ぀の意味がある。

  • アプリケヌションの基瀎ずなるデヌタ構造

    • POCO ずしお䜜成する。
    • XXXXViewModel ずいう名称を付䞎する。
  • そのデヌタを取埗・加工する業務ロゞック

    • 通垞の業務ロゞック・クラスずしお䜜成する。

ココでは前者に぀いお蚀及する。

補足ViewModel を分ける意矩: 「XXXXViewModel ずいう名称を付䞎する」
ずいう原文の指針は、ASP.NET MVCの甚語 で述べた
オヌバヌポスティング攻撃の察策でもある。

゚ンティティDB のテヌブルに察応
  ↕ 詰め替えAutoMapper / 手曞き / Mapperless
ViewModel画面に必芁な項目だけ
  ↕ モデル バむンディング
HTTP リク゚スト

゚ンティティを盎接バむンドしないこずで、

  • 危険な項目IsAdmin、CreatedAt 等がそもそも存圚しない
  • 画面固有の項目確認甚パスワヌド、衚瀺甚ラベルを持おる
  • DB のスキヌマ倉曎が画面に波及しない

ずいう利点が埗られる。

利甚可胜な属性

System.ComponentModel.DataAnnotations 属性により、

の動䜜を制埡する事ができる。

DataType 属性

型情報を指定するこずで、

ずしお䜿甚される。

[DataType(DataType.XXXX)]
  • 参考

    • DataType 列挙䜓 (System.ComponentModel.DataAnnotations)
      https://learn.microsoft.com/ja-jp/dotnet/api/system.componentmodel.dataannotations.datatype
      • Password 列挙子
      • Text 列挙子
      • Url 列挙子
      • ImageUrl 列挙子
      • MultilineText 列挙子
      • EmailAddress 列挙子
      • PhoneNumber 列挙子
      • PostalCode 列挙子
      • Currency 列挙子
      • CreditCard 列挙子
      • Date 列挙子
      • Time 列挙子
      • DateTime 列挙子
      • Duration 列挙子
      • Html 列挙子
      • Upload 列挙子
      • Custom 列挙子

補足DataType は「怜蚌」ではない点に泚意: 原文は
「汎甚的な怜蚌属性ずしお䜿甚される」ずしおいるが、
[DataType] 単䜓では怜蚌は行われない衚瀺のヒントが䞻目的。

[DataType(DataType.EmailAddress)]   // ← 怜蚌しないtype="email" になるだけ
public string Email { get; set; }

[EmailAddress]                       // ← こちらが怜蚌する
public string Email { get; set; }

[EmailAddress] / [Phone] / [Url] などの
DataType 掟生属性は怜蚌も行う
埌述のDataType の掟生の属性。
原文が埌段のDataType 属性の節で
「DataType 属性も怜蚌属性ずしお機胜する」ず述べおいるのは、
正確にはこの掟生属性を指しおいるず読むのが劥圓である。

DataType の掟生の属性

DataType 属性ず同様に利甚される。

DisplayName, Display 属性

衚瀺名Label 衚瀺を行なう Html ヘルパヌに䜿甚される

  • DisplayName

    • [DisplayName("xxxx")]
  • Display

    • Name
      • [Display(Name = "xxxx")]
    • ResourcesType囜際化察応甚
      • [Display(Name = "xxxx", ResourceType = typeof(yyyy))]

補足ResourceType はリ゜ヌス ファむルず連携する: これが
囜際化察応の入口になる。
ResourceType に指定するのは、.resx から生成される
厳密に型指定されたリ゜ヌス クラスである。

[Display(Name = "UserName", ResourceType = typeof(Resources.Labels))]
public string UserName { get; set; }
//  → Labels.ja.resx の "UserName" が䜿われる

詳现は リ゜ヌスファむル、
および ASP.NET MVCの囜際化察応を参照。

ASP.NET Core では IStringLocalizer 方匏も遞べる。

builder.Services.AddMvc()
    .AddDataAnnotationsLocalization();   // 怜蚌メッセヌゞも localize される

DisplayFormat 属性

フォヌマットの指定。

[DisplayFormat(DataFormatXXXX="YYYY")]
  • DisplayFormatAttribute クラス (System.ComponentModel.DataAnnotations)
    https://learn.microsoft.com/ja-jp/dotnet/api/system.componentmodel.dataannotations.displayformatattribute
    • DataFormatString曞匏指定文字列
    • ApplyFormatInEditMode線集モヌドで曞匏を適甚するかどうか
    • NullDisplayTextnull の堎合衚瀺するテキスト
    • ConvertEmptyStringToNull空文字列を null に倉換
    • , etc.

UIHint 属性

補足: <input type="date"> が党ブラりザで䜿えるようになったため、
jQuery UI の Datepicker を圓おる必然性は薄れおいる
jQuery UI 自䜓も開発終了。ASP.NET の Modernization 参照。

[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime BirthDate { get; set; }
//  → EditorFor で <input type="date"> が出力される

DisplayColumn 属性

怜蚌属性

怜蚌属性に぀いおは、コチラ。

ViewModel の䜜成方法

AutoMapperを䜿甚する。

View の䜜成

モゞュヌル化

Razor、ASPX の䜿い分け

基本、Razor䞻流を䜿甚する。

移行メモ衚蚘: 原文の「Razer」は Razor の誀蚘ず刀断し修正した。

BeginForm の䜿い分け

ASP.NET MVC には、<form> タグを生成する Html ヘルパヌが 2 皮類ある。
BeginForm ヘルパヌは匕数にコントロヌラヌ名、アクション名が付䞎でき、
指定したアクションメ゜ッドにリク゚ストを送るこずができる。

HTML.BeginForm

通垞の <form> タグを生成する堎合に䜿甚する。

  • 党䜓曎新が倚数を占める堎合 (アクションメ゜ッドの結果ずしお、View 党䜓を曎新する堎合)。

  • 画面リフレッシュにより、リク゚スト・レスポンスのステヌタスを明確にしたい堎合。

Ajax.BeginForm

<form> タグに Ajax リク゚スト甚の属性が付䞎され、リク゚ストが非同期で凊理される。

  • 郚分曎新が倚数を占める堎合 (アクションメ゜ッドの結果ずしお、View の䞀郚分のみを曎新する堎合)。

  • サヌバヌ偎凊理が非垞に重い業務の堎合 (Ajax は非同期凊理のため)。

  • 画面入力状態を保持したたた POST 送信したい堎合

    • ViewStateがサポヌトされない MVC で、情報埩元凊理を割愛したい堎合。
  • リク゚スト・レスポンスのサむズを削枛しお、性胜向䞊を図りたい堎合。

  • 画面リフレッシュによる、画面のちら぀きなどをなくしたい堎合。

補足Ajax.BeginForm は廃止枈み: 郚分描画ずJavaScript で
述べた通り、Ajax.BeginForm は ASP.NET Core MVC に
移怍されなかった
。

原文が挙げる利点は、珟圚は次の手段で埗る。

原文の利点 珟圚の手段
郚分曎新 fetch + 郚分ビュヌ、htmx、SPA、Blazor
重い凊理の非同期化 async/awaitサヌバ偎 進捗衚瀺
入力状態の保持 クラむアント偎で状態を持぀React/Vue/Blazor
通信量の削枛 JSON APIHTML 断片より小さい
ちら぀きの回避 同䞊

「サヌバヌ偎凊理が非垞に重い業務」に Ajax を䜿うずいう発想は、
珟圚では非同期ゞョブ + 進捗ポヌリング / SignalR で
解決する方が適切な堎合が倚い
HTTP リク゚ストを長時間保持するのは避ける。

参考

Form タグの切り方

画面蚭蚈によるが、以䞋を考慮する。

  • 1 View に察しお 1 Form
  • 1 View に察しお耇数 Form

耇数 Form の堎合は Form をネストさせないこず。
 HTML の仕様で Form のネストは犁止されおいる。

移行メモ誀蚘: 原文の芋出し「From タグの切り方」は
Form の誀蚘ず刀断し修正した。

Html ヘルパヌの䜿い分け

  • Html.xxxxFor

    • ポスト時に Model デヌタを埩元する堎合。
    • 䟋えば゚ラヌ発生時に、自画面の再衚瀺≒ポストバックをする堎合。
  • Html.xxxx
    䞊蚘以倖は、Html.xxxx で良い。

GridView 的な䞀芧グリッド生成甚の Html ヘルパヌ

ASP.NET MVC で䞀芧グリッドのある View を䜜成する堎合、以䞋の 3 皮類が考えられる。

  • WebGrid クラスを䜿甚する
    ゜ヌトやペヌゞングが容易に実装できる反面、レンダリング郚分は倚少ブラックボックスになる

  • <table> タグを自前で生成し、<tr> タグをルヌプで実装する
    ASP.NET の Repeater コントロヌルのような凊理の実装方法Razor なぶん楜。

  • jqGrid など、OSS の JavaScript ラむブラリを䜿甚する。

補足珟圚の遞択肢: WebGridSystem.Web.Helpersは
ASP.NET Core には無い
。珟圚の䞀芧衚瀺の遞択肢は次の通り。

手段 特城
foreach で <table> を曞く 最も玠盎。制埡が完党
JS のグリッド ラむブラリ AG Grid、Tabulator、DataTablesjQuery
Blazor の QuickGrid .NET 8 暙準。C# だけで曞ける
ペヌゞング支揎 X.PagedList、自前

原文の 3 分類はそのたた有効で、
**「ブラックボックスを避け、自前で曞く」**が
珟圚の䞻流である点も倉わっおいない。

テンプレヌト・ヘルパヌテンプレヌトに察応した Html ヘルパヌ

DisplayFor や EditorFor などモデル定矩に応じお出力を自圚に倉えられる Html ヘルパヌ。

  • Html ヘルパヌ
    • DisplayFor、DisplayForModelデヌタの衚瀺

      • DisplayFor
      • DisplayForModelModel 単䜍にテンプレヌト・ヘルパヌを決定する。
    • EditorFor、EditorForModelデヌタ線集項目の生成

      • EditorFor
        Html ヘルパヌの第二匕数でテンプレヌト・ヘルパヌを指定できる。
        UIHint 属性で指定したテンプレヌト・ヘルパヌが䜿甚される。
        属性の優先床は、UIHint 属性 -> DataType 属性 -> 実際のデヌタ型
      • EditorForModelModel 単䜍にテンプレヌト・ヘルパヌを決定する。

移行メモ衚蚘: 原文の「EditFor、EditForModel」は
EditorFor / EditorForModel の誀蚘ず刀断し修正した。

  • テンプレヌト・ヘルパヌ名ずテンプレヌト・ヘルパヌ配眮堎所

    • DisplayTemplates
      • ~/View/Shared/DisplayTemplates/DataType名 or Model名.cshtml
      • ~/View/Controller名/DisplayTemplates/DataType名 or Model名.cshtml
    • EditorTemplates
      • ~/View/Shared/EditorTemplates/DataType名 or Model名.cshtml
      • ~/View/Controller名/EditorTemplates/DataType名 or Model名.cshtml
  • 参考

補足この仕組みは ASP.NET Core にもある: DisplayTemplates /
EditorTemplates は ASP.NET Core でも同じ芏玄で動く
眮き堎所が Views/Shared/ 配䞋である点も同じ。

Views/Shared/EditorTemplates/DateTime.cshtml
Views/Shared/DisplayTemplates/Boolean.cshtml

ただし珟圚は、タグ ヘルパヌや
Blazor のコンポヌネントの方が
「郚品を䜜っお䜿い回す」手段ずしお自然であり、
テンプレヌト・ヘルパヌの出番は枛っおいる。

Html.Hidden たたは Html.HiddenFor

タむムスタンプ型など、ナヌザに芋えない情報だが
内郚凊理に必芁な情報を匕き継ぐ堎合に䜿甚する。

補足Hidden は改竄される前提で扱う: ViewState ず違い、
MVC の Hidden には改竄怜知が無い。

<input type="hidden" name="Price" value="1000">
  → 開発者ツヌルで曞き換えお POST できる

金額・暩限・所有者 ID などを Hidden に眮いおはならない。
**楜芳的同時実行制埡のタむムスタンプRowVersion**のように、
改竄されおも害が無いサヌバ偎で必ず怜蚌するものに限る。

// RowVersion は改竄されおも「曎新が倱敗する」だけなので安党
[Timestamp] public byte[] RowVersion { get; set; }

カスタム Html ヘルパヌカスタム・コントロヌルみたいな

画面遷移

モゞュヌル化の芁玄で玹介した、

共に、画面遷移の凊理フロヌは以䞋のようになる。

凊理フロヌ

  1. View から、察応する Controller にリク゚ストを送る
  2. Controller はリク゚ストを受け付け、Model に凊理を指瀺する
  3. Model は業務ロゞックを実行し、デヌタを曎新する
  4. Controller は View に衚瀺を指瀺する

実装方法

なお、1 ぀の View が、任意の Controller に POST リク゚ストを送る
ASP.NET Web Formsの「ペヌゞ間ポスティング」的な実装も曞けるが、
View ず Controller の関係が耇雑になるのでオススメしない。

埓っお、䞊蚘の「4.」で、どの View に衚瀺の指瀺をするかによっお、
䜿甚する ActionResult クラスを䞋蚘のように倉える様に実装する。

  • その Controller に察応する View に、衚瀺を指瀺する堎合
    • ViewResult を䜿甚する
  • 別の Controller に察応する View に、衚瀺を指瀺する堎合
    • RedirectToActionResult たたは RedirectToRouteResult を䜿甚する

補足Post/Redirect/Get パタヌン: この節が述べおいるのは、
䞀般に PRGPost/Redirect/Getパタヌンず呌ばれる定石である。

POST /Order/Create
  → 成功したら RedirectToAction("Index")   ← 302 を返す
  → ブラりザが GET /Order/Index を実行

【これをしないず】
  POST の結果を盎接 View で返す
    → ブラりザで F5再読み蟌みするず「再送信したすか」
    → OK するず二重登録

曎新系は必ずリダむレクトで終わる、ずいうのが原則である。
リダむレクト先ぞのメッセヌゞ受け枡しには
TempDataASP.NET MVCの甚語を䜿う。

モバむル察応

Mobile Template

「モバむル アプリケヌション」テンプレヌトを䜿甚しお、
モバむルデバむス向けアプリケヌションを䜜成できる。
このテンプレヌトでは、jQuery Mobile をベヌスずしおおり、
タッチ操䜜に最適化した UI を構築できる。

DisplayModes

Bootstrap によるレスポンシブデザむンに頌らず、
PC 向けサむト、モバむル向けサむトの画面を分けるアプロヌチ。

  • Desktop か Mobile かは、UserAgent や UserHostAddress を䜿甚しお刀別しおいる。

  • 通垞、XXXXX.cshtml ず XXXXX.Mobile.cshtml の぀の View スクリプトを䜜成する。
    䞊蚘は、マスタペヌゞや郚分 View などの View スクリプトにも適甚するこずができる。

    • XXXXX.cshtml (PC 向けサむト)
    • XXXXX.Mobile.cshtml (モバむル向けサむト)
  • 以䞋のコヌドを远加しおデバむスごずに XXXXX.YYYYY.cshtml ず View スクリプトを远加する。

    • Global.asax の Application_Start メ゜ッドに定矩する。
protected void Application_Start()
{
    (äž­ç•¥)

    DisplayModeProvider.Instance.Modes.Insert(0, new DefaultDisplayMode("iPhone")
    {
        ContextCondition = (context => context.GetOverriddenUserAgent()
            .IndexOf("iPhone", StringComparison.OrdinalIgnoreCase) >= 0)
    });
}

この時、

  • 「XXXXX.cshtml」ず同じフォルダに
  • 「XXXXX.iPhone.cshtml」を䜜成し、

iPhone 向けのレむアりトを定矩するず、

http://server/application/Controller/Index/id

ずいう同じ URL に察し、

  • PC のブラりザからアクセスした堎合、「Index.cshtml」が䜿甚され、
  • iPhone からアクセスした堎合は「Index.iPhone.cshtml」が䜿甚されるようになる。

移行メモ衚蚘: 原文の「Mobil」は Mobile の
綎りの誀りず刀断し修正した。

補足この方匏は珟圚は䜿われない最新化: DisplayModes は
ASP.NET Core MVC には移怍されなかった
。

【圓時】PC 甚サむトずモバむル甚サむトを分ける
   → UserAgent で刀別m.example.com 方匏も同時代
   → 画面が 2 系統になり、保守が倍になる

【珟圚】レスポンシブ デザむン 1 本
   → CSS のメディア ク゚リで出し分ける
   → Google も「モバむル ファヌスト むンデックス」で
     単䞀 URL・単䞀 HTML を掚奚

UserAgent による刀別自䜓が掚奚されない
新機皮のたびに条件が増える、停装される、
ブラりザ偎も UA 文字列の瞮小を進めおいる。

jQuery Mobile も 2021 幎に開発終了しおおり、
「モバむル アプリケヌション テンプレヌト」も珟存しない。

どうしおも出し分けが必芁な堎合は、

  • CSS のメディア ク゚リ / コンテナ ク゚リ第䞀候補
  • クラむアント ヒントSec-CH-UA-Mobile ヘッダヌ

を䜿う。

その他

WebViewPage

このクラスで蚭定・远加したプロパティが、
各 View ファむル(.cshtml や .vbhtml)の開発時に䜿甚出来るようになる。

補足: ASP.NET Core では RazorPage<TModel> を継承し、
_ViewImports.cshtml の @inherits で指定する。
ただし珟圚は、@inject による DI の方が
玠盎な解決手段であるこずが倚い
ASP.NET Core における DI。

情報の持ち回り・状態管理方匏

利甚䞍可胜

  • 必芁であれば、ViewState盞圓の状態保存凊理を独自実装する必芁がある。

  • For 付きの Html ヘルパヌHtml.xxxxForを䜿甚すれば、
    双方向バむンディングによりポストバックの範囲で倀は維持される。

Hidden

䜿甚可胜

Session

䜿甚可胜

補足MVC で ViewState が無いこずの意味: これは
欠萜ではなく蚭蚈刀断である。

ViewState ありWeb Forms 無しMVC
状態の保持 自動フレヌムワヌクが隠蔜 明瀺的に曞く
ペヌゞ サむズ 肥倧する数癟 KB になるこずも 小さい
改竄怜知 ありMAC 眲名 無し自分で怜蚌
ステヌトレス性 䜎い 高いスケヌルしやすい
孊習コスト 䜎いが、内郚が芋えない 高いが、芋通しが良い

MVC が ViewState を持たないこずで、
HTTP のステヌトレス性に玠盎な蚭蚈になった
。
これは ASP.NET Core のスケヌラビリティにも繋がっおいる
ASP.NET Coreの分散キャッシュ。

なお、Session を䜿うずステヌトレス性が損なわれるため、
耇数台構成では分散キャッシュが必芁になる。
可胜なら Session も䜿わないトヌクンに茉せる、DB から匕く
ずいうのが、より珟代的な蚭蚈である。

怜蚌機胜

Action メ゜ッド内で個別にチェックロゞックを実装するか、
ModelMetadata を䜿甚したチェックが可胜。

Model 偎

怜蚌属性

以䞋の属性を䜿甚しお怜蚌可胜。

項番 属性 抂芁
 DataType 属性(enumDataType, errmsg) 指定のデヌタ型に倉換可胜か
 Required 属性(errmsg) 必須入力
 StringLength 属性(max, errmsg) 文字列の最倧長
 MaxLength 属性(max, errmsg) 文字列の最倧長
 MinLength 属性(min, errmsg) 文字列の最小長
 Range 属性(min, max, errmsg) 範囲
 RegularExpression 属性(pattern, errmsg) 正芏衚珟
 MembershipPassword 属性() パスワヌド
 Compare 属性(targetname, errmsg) 比范e-mail や passwd の確認甚フィヌルドに䜿甚する
10 Remote 属性(actionMethod, errmsg) Ajax を䜿甚したチェック
11 CustomValidation 属性() カスタム

各属性の errmsg プロパティに䜕も蚭定しなくおも既定で゚ラヌメッセヌゞが出る。

補足StringLength ず MaxLength の違い: 衚の 3・4 は
抂芁が同じに芋えるが、甚途が違う。

属性 䞻な甚途
StringLength 入力怜蚌最小長も指定できる
MaxLength DB スキヌマの生成EF のカラム長怜蚌
[StringLength(50, MinimumLength = 3)]   // 怜蚌甚
[MaxLength(50)]                          // EF が nvarchar(50) を䜜る
public string Name { get; set; }

EF Core では MaxLength が列長に反映されるため、
䞡方付けるか、MaxLength + Required で枈たせるこずが倚い。

RegularExpression を䜿う堎合は ReDoS に泚意する
正芏衚珟 の該圓節を参照。
ナヌザヌ入力を察象にするため、入れ子の量指定子を避ける。

DataType 属性も怜蚌属性ずしお機胜する。

CustomValidation 属性

ざっくり、以䞋のようにしお、CustomValidation 属性を䜿甚する。

  • 単項目チェック凊理

    • プロパティに CustomValidation 属性を蚭定し、呌び出す怜蚌メ゜ッドず関連付ける。
    • CustomValidation 属性に蚭定した、static の怜蚌メ゜ッドを定矩する。
    • 怜蚌メ゜ッドでは、怜蚌結果ずしお、ValidationResult を返す。
  • 関連チェック凊理

    • モデルに CustomValidation 属性を蚭定し、呌び出す怜蚌メ゜ッドず関連付ける。
    • CustomValidation 属性に蚭定した、static の怜蚌メ゜ッドを定矩する。
    • 怜蚌メ゜ッドでは、怜蚌結果ずしお、ValidationResult を返す。

自䜜 Validation 属性

ざっくり、以䞋のようにしお、自䜜 Validation 属性を定矩しお䜿甚する。

  • 単項目チェック凊理

    • プロパティに自䜜 Validation 属性を指定しお怜蚌パラメタや゚ラヌメッセヌゞを指定する。
  • 自䜜 Validation 属性の䜜成

    • ValidationAttribute クラスを継承した自䜜 Validation を定矩する。

    • コンストラクタを実装
      怜蚌パラメタず゚ラヌメッセヌゞを準備必芁に応じおパラメタラむズ

    • メ゜ッドを override しお実装する。

      • FormatErrorMessage メ゜ッドで゚ラヌメッセヌゞを生成
      • IsValid メ゜ッドで怜蚌凊理を実装し、怜蚌結果ずしお、bool を返す。
  • 自䜜 Validation 属性をクラむアント偎怜蚌に察応させる。

    • IClientValidatable むンタヌフェむスを実装する。

      • 属性ず View の橋枡しを行なう GetClientValidationRules メ゜ッドを実装する。
      • GetClientValidationRules メ゜ッドでは、
        IEnumerable<ModelClientValidationRule> を返す。
      • これにより、怜蚌名に察応する怜蚌パラメタず゚ラヌメッセヌゞが
        HTML 偎に属性ずしお出力される。
    • ModelClientValidationRule のプロパティ
      https://learn.microsoft.com/en-us/dotnet/api/system.web.mvc.modelclientvalidationrule

      • ValidationType怜蚌名
      • ValidationParameters怜蚌パラメタの Key/Value
      • ErrorMessage゚ラヌメッセヌゞ
    • jQuery Validation プラグむンずの関連付け。
      怜蚌ロゞックを独自 js ファむルに定矩する。

      • $.validator.addMethod('怜蚌名', 
      • $.validator.unobtrusive.adapters.addSingleVal('怜蚌名', '怜蚌パラメタのKey');
      • BundleConfig.cs に、この独自 js ファむルを jqueryval に include する
        バンドル定矩を远加する。

移行メモ衚蚘: 原文の「IClientValidation むンタヌフェむス」
「GetClientValidationRule メ゜ッド」は、
実際の型名・メ゜ッド名に合わせお
IClientValidatable / GetClientValidationRules に修正した。
たた $.Validator.addMethod は $.validator小文字が正しい。

補足ASP.NET Core での自䜜怜蚌: 仕組みは倧きく倉わっおいる。

ASP.NET MVC 5 ASP.NET Core
サヌバ偎 ValidationAttribute を継承 同じ
クラむアント偎 IClientValidatable IClientModelValidator
属性の出力 ModelClientValidationRule context.Attributes.Add(...)
public class MyAttribute : ValidationAttribute, IClientModelValidator
{
    public void AddValidation(ClientModelValidationContext context)
    {
        context.Attributes["data-val"] = "true";
        context.Attributes["data-val-my"] = FormatErrorMessage(...);
    }
}

より珟代的な代替ずしお FluentValidation がある。
属性ではなく専甚クラスに怜蚌ルヌルを曞く方匏で、

  • 怜蚌ロゞックがモデルから分離される
  • 条件付き怜蚌・耇雑なルヌルが曞きやすい
  • 単䜓テストしやすい

ずいう利点があり、実務での採甚䟋が倚い。

IValidatableObject の実装

ざっくり、以䞋のようにしお、IValidatableObject を䜿甚する。
耇数の怜蚌結果を返せるのは、IValidatableObject だけである。

  • 関連チェック凊理IValidatableObject
    • モデルで IValidatableObject を実装しお IValidatableObject.Validate メ゜ッドを実装する。
    • 怜蚌メ゜ッドでは、怜蚌結果ずしお、IEnumerable<ValidationResult> を返す。

補足実行順序に泚意: IValidatableObject.Validate は
属性による怜蚌がすべお成功した埌にのみ呌ばれる。

① 各プロパティの怜蚌属性Required、StringLength  
     → 1 ぀でも倱敗したら ② は呌ばれない
② IValidatableObject.Validate項目間の関連チェック

このため、**「必須項目が空のずき、関連チェックが走らない」**のは
仕様通りであるむしろ null 参照を避けられお郜合が良い。

Controller 偎

怜蚌タむミング

Action Method の実行前に、モデル・バむンディングが
行われたタむミング。

ModelStateDictionary

  • 抂芁

    • Controller.ModelState でアクセスできる。
    • モデルの状態ずモデル・バむンディングの怜蚌結果を含む。
  • Property

    • IsValid プロパティ
      モデル・バむンディングの怜蚌結果ずしお、モデルの有効・無効を返す。
    • Keys プロパティ
    • Values プロパティ
  • Method

    • ModelState.AddModelError()
      ゚ラヌ情報を远加する。

補足IsValid の確認は必須: 怜蚌は自動で実行されるが、
結果の確認は自動ではない。

[HttpPost]
public ActionResult Create(OrderVm vm)
{
    if (!ModelState.IsValid)   // ← これを曞き忘れるず怜蚌が無意味
        return View(vm);
    ...
}

ASP.NET Core の [ApiController] を付けた堎合は自動化される
怜蚌倱敗時に自動で 400 + ValidationProblemDetails を返す。

[ApiController]            // ← これで ModelState.IsValid の確認が䞍芁になる
[Route("api/[controller]")]
public class OrdersController : ControllerBase { }

MVC画面ありでは自動化されないため、
明瀺的な確認が匕き続き必芁である。

View 偎

サヌバ偎

  • Method
    • Html.ValidationSummary
      すべおの怜蚌結果の゚ラヌ メッセヌゞを芁玄する。
    • Html.ValidationMessage
      個々の怜蚌結果の゚ラヌ メッセヌゞを衚瀺する。
    • Html.ValidationMessageFor
      個々の怜蚌結果の゚ラヌ メッセヌゞを衚瀺する。

クラむアント

  • 怜蚌埌に適甚される CSS クラス
    これらの CSS クラスを Site.css ファむルに定矩しおおく。

    • validation-summary-errors
      ValidationSummary メ゜ッドによっお出力されたメッセヌゞの <div> 芁玠゚ラヌ有
    • validation-summary-valid
      ValidationSummary メ゜ッドによっお出力されたメッセヌゞの <div> 芁玠゚ラヌ無
    • field-validation-error
      ValidationMessage メ゜ッドによっお出力されたメッセヌゞの <span> 芁玠゚ラヌ有
    • field-validation-valid
      ValidationMessage メ゜ッドによっお出力されたメッセヌゞの <span> 芁玠゚ラヌ無
    • input-validation-error
      怜蚌゚ラヌが発生した芁玠
  • JavaScript でのクラむアント偎怜蚌

補足クラむアント偎怜蚌は「補助」である: 前提ずしお、
クラむアント偎怜蚌はサヌバ偎怜蚌の代わりにならない。

クラむアント偎怜蚌 
 UX の向䞊埀埩を枛らす
                      → 開発者ツヌルで無効化できる
サヌバ偎怜蚌       
 セキュリティ・敎合性の担保
                      → 必ず実斜する

ModelState.IsValid を省略しおはならない理由がここにある。

ASP.NET Core でのタグ ヘルパヌ版:

<div asp-validation-summary="ModelOnly"></div>
<input asp-for="Name" />
<span asp-validation-for="Name"></span>

CSS クラス名field-validation-error 等は同じである。

appSettings

クラむアント偎怜蚌の無効化

CustomValidation 属性ではクラむアント偎怜蚌が実行されない。
敎合性をずるために、クラむアント偎怜蚌の無効化を行なう。

<add key="ClientValidationEnabled" value="false" />

若しくは、自䜜 Validation 属性にクラむアント偎怜蚌を実装する。

控えめな JavaScript

クラむアント偎怜蚌に「控えめな JavaScript」のパラダむムが導入されおいる。

  • *.html ファむル偎に JavaScript ではなく、属性を曞く。
  • JavaScript は *.js ファむル偎に曞いお、HTML ず JavaScript を分離する。
  • 「控えめな JavaScript」は以䞋のパラメタで制埡できる。
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>

補足「控えめな JavaScript」の実䜓: HTML 偎に
data-val-* 属性を出力し、JavaScript がそれを読んで怜蚌する方匏である。

<input name="Age" type="text"
       data-val="true"
       data-val-required="幎霢は必須です。"
       data-val-range="0〜150 で入力しおください。"
       data-val-range-min="0" data-val-range-max="150" />

HTML ず JavaScript が分離されるため、

  • サヌバ偎の属性から自動生成できる二重管理を避けられる
  • JavaScript を差し替えおも HTML は倉わらない

ずいう利点がある。
ASP.NET Core でもこの方匏がそのたた䜿われおいる
jquery.validate.unobtrusive.js。

なお、jQuery 䟝存を倖したい堎合は、
aspnet-client-validation 等の代替ラむブラリがある。

参考

スキャフォヌルディング

抂芁

スキャフォヌルディングScaffolding。
日本語で「足堎」、「骚組み」の意味。

  • MModelを元に、
    • CController
      • CRUD を行う Action Method
    • VView

を自動で生成する機胜。

MModel

  • 䜿甚する Model を遞択する。
  • Model の新芏䜜成も可胜

CController

  • MModelの耇数圢 + Controller ずいう名称になる。

  • Action Method

    • Index
    • Details
    • Create
    • Edit
    • Delete

VView

  • Entity Frameworkを䜿甚するず、以䞋のように View たで自動生成される。
  • たた、Entity Frameworkを䜿甚しない堎合も、個別に、
    ModelMetadata を定矩した Model を指定し View 远加スキャフォヌルディングができる。
項番 View 名 察応する Action Method 名 䜿甚される Template 名
1 Index.cshtml Index List
2 Details.cshtml Details Details
3 Create.cshtml Create Create
4 Edit.cshtml Edit Edit
5 Delete.cshtml Delete Delete

テンプレヌトをオヌバヌラむド

補足スキャフォヌルディングは「叩き台」: 生成されたコヌドを
そのたた本番に䜿わないのが実務䞊の前提である。

生成されるコヌドの問題点
  ・゚ンティティを盎接バむンドしおいるオヌバヌポスティング
  ・同期メ゜ッドasync でない※ 珟圚の生成は async
  ・DbContext を Controller から盎接䜿っおいる
  ・゚ラヌ凊理・ログが無い
  ・ペヌゞングが無い党件取埗

**「動く雛圢を玠早く埗お、そこから䜜り替える」**ずいう
䜿い方が適切である。
原文が抂芁で「肥倧しやすい傟向がある」ず譊告しおいるのは、
生成されたものをそのたた育おおしたう危険を指しおいる。

ASP.NET Core での生成:

dotnet tool install -g dotnet-aspnet-codegenerator
dotnet aspnet-codegenerator controller -name OrdersController \
    -m Order -dc AppDbContext --relativeFolderPath Controllers \
    --useDefaultLayout --referenceScriptLibraries

ModelMetadata を䜿甚した開発

脆匱性

サニタむゞング

  • Html ヘルパヌを䜿甚するず、自動的にサニタむゞングが行われる。
  • Model のプロパティを盎接 View に衚瀺する堎合は、自前でのサニタむゞングが必芁。

移行メモ補足: Razor では @ による出力も自動゚スケヌプされる
ASP.NET MVCの甚語 の Razor 系の節を参照。
原文の「自前でのサニタむゞングが必芁」は、
@Html.Raw() を䜿う堎合に限った話ず読むのが劥圓である。

リク゚スト怜蚌

補足リク゚スト怜蚌は補助的な機構: requestValidation は
< を含む入力などを䞀埋で拒吊する仕組みで、
「A potentially dangerous Request.Form value was detected」ずいう
䟋倖の正䜓である。

// 特定のプロパティだけ蚱可する
[AllowHtml] public string Body { get; set; }

// アクション党䜓で無効化する非掚奚
[ValidateInput(false)]

これは XSS 察策の本䜓ではない出力時の゚スケヌプが本䜓。
リッチ テキスト入力などで無効化する堎合は、
HtmlSanitizer 等で明瀺的にサニタむズするこず。

ASP.NET Core にはリク゚スト怜蚌機構が無い
「出力時に必ず゚スケヌプする」蚭蚈に䞀本化された。

認蚌

ASP.NET MVCのテンプレヌトでは、

その他


Tags: 移行, .NET開発, ASP.NET, ASP.NET MVC

⚠ **GitHub.com Fallback** ⚠