第26章 ASP.NET Core MVC 入門:占いアプリ
この章の目的
Section titled “この章の目的”この章から、もう一つの大きなアプリ形式 ── Web アプリ(ASP.NET Core MVC) に入ります。
第 18〜25 章では、PC 上で起動する Windows フォームアプリ を作りました。 これから扱う Web アプリは、ブラウザ からアクセスして使うアプリです。
Windows フォーム: PC 上でアプリを直接起動 → フォーム画面が出るWeb アプリ: ブラウザで URL を開く → HTML 画面が出るこの章では、ちょっと遊び心のある 「占いアプリ」 を題材にして、MVC の基本を体験します。データベースはまだ使いません。Model・View・Controller の役割分担 と、ブラウザとサーバーのやり取り を理解することが目的です。
この研修での Web アプリ編の進め方
Web アプリは本格的に作ろうとすると、必要な要素がたくさんあります。 本研修では時間に余裕がないため、「動作の仕組みを理解する」ことに重点 を置きます。 Visual Studio が用意してくれる MVC テンプレート をそのまま使い、小さな改造で動かしながら、次の 3 つを理解することを目指します。
- リクエストとレスポンス ── ブラウザから情報が送られ、HTML が返ってくる
- GET と POST の違い ── 画面を見るときと、入力を送るときで方法が違う
- MVC の役割分担 ── Controller・Model・View の 3 つに役割を分けている
自分でゼロから複雑な Web アプリを組めるレベルは目指しません。 後で必要になったときに、「あ、これは Controller だな」と読み解ける状態を目指します。
この章でできるようになること
Section titled “この章でできるようになること”この章を終えると、次のことができるようになります。
- ASP.NET Core MVC プロジェクトを Visual Studio で作成できる
- Controller・Model・View の役割を自分の言葉で説明できる
- GET と POST の違いを説明できる
- URL とコントローラー・アクションの対応を読める
- フォーム送信したデータが Controller に届く仕組み(Model Binding)の概要を説明できる
- View で Model のプロパティを表示する書き方が分かる
- 入力画面と結果画面の 2 画面構成 を組み立てられる
- Windows フォームアプリとの違いを説明できる
本章で使用する環境
Section titled “本章で使用する環境”| 項目 | 内容 |
|---|---|
| 開発環境 | Visual Studio 2022 |
| プロジェクト種類 | ASP.NET Core Web アプリ(Model-View-Controller) |
| 対象フレームワーク | .NET 8 |
| ソリューション名 | Chapter26 |
| プロジェクト名 | Ch26_MvcFortuneApp |
| 認証の種類 | なし |
| HTTPS 用の構成 | 既定のまま |
csproj の Nullable は disable に変更してください
プロジェクト作成後、
Ch26_MvcFortuneApp.csprojを開いて<Nullable>disable</Nullable>に変更してください(第 1 章「1-1」参照)。 Web アプリでも本研修では Nullable disable で統一します。
作業前チェック
Section titled “作業前チェック”- 第 25 章を Git に提出済みである
- Visual Studio で「ASP.NET Core Web アプリ(Model-View-Controller)」テンプレートが選べる
- ブラウザで
https://localhost:xxxx/を開ける(Visual Studio が自動で起動するブラウザ)
26-1 Web アプリの動作イメージ
Section titled “26-1 Web アプリの動作イメージ”Web アプリは、ブラウザとサーバーのやり取り で動きます。
[ブラウザ] [サーバー = あなたが作る Web アプリ]
URL を入力 ──→ リクエスト ──→ Controller が受け取る (例: /Fortune/Index) ↓ 画面を組み立てる(View) ↓ HTML を画面に表示 ←── レスポンス ←── HTML を返すこのやり取りを リクエスト と レスポンス といいます。
| 用語 | 内容 |
|---|---|
| リクエスト | ブラウザがサーバーに「この URL を見せて」とお願いする |
| レスポンス | サーバーがブラウザに「これが画面の HTML です」と返す |
Web アプリのプログラムを書くということは、「リクエストを受けて、どんなレスポンスを返すか」を決めるコードを書く ということです。
26-2 MVC とは
Section titled “26-2 MVC とは”MVC は、Web アプリの中身を 3 つの役割に分ける 考え方です。
| 役割 | 担当 |
|---|---|
| Model | 画面で扱うデータの形 |
| View | 画面に表示する HTML |
| Controller | リクエストを受け取り、処理の流れを決める |
| MVC | この章の占いアプリでの例 |
|---|---|
| Model | 入力された名前・生年月日・気分と、占い結果を持つ FortuneViewModel |
| View | 入力フォーム Index.cshtml、占い結果 Result.cshtml |
| Controller | 入力を受け取って結果を作る FortuneController |
3 役のやり取りを図にすると、次のような流れになります。
ブラウザが最初に話しかけるのは 必ず Controller です。 Controller が司令塔となって Model にデータを頼み、View に表示を任せ、最終的に View が組み立てた HTML がブラウザに返ります。
役割が分かれていると:
- Controller を読めば「どんな URL でどんな処理が動くか」が分かる
- Model を読めば「画面で何のデータを扱うか」が分かる
- View を読めば「画面の見た目」が分かる
役割を意識してコードを読むことが、Web アプリ理解の第一歩です。
26-3 Visual Studio で MVC プロジェクトを作成する
Section titled “26-3 Visual Studio で MVC プロジェクトを作成する”新しいプロジェクトを作ります。
| 項目 | 値 |
|---|---|
| テンプレート | ASP.NET Core Web アプリ(Model-View-Controller) |
| ソリューション名 | Chapter26 |
| プロジェクト名 | Ch26_MvcFortuneApp |
| フレームワーク | .NET 8.0 |
| 認証の種類 | なし |
| HTTPS 用の構成 | 既定のままチェックを入れる |
| Docker の有効化 | チェックを外す |
作成したら、Ch26_MvcFortuneApp.csproj を開いて <Nullable>disable</Nullable> に変更します。
そして 何も改造せずに F5 で実行 してみてください。 Visual Studio が自動でブラウザを起動し、テンプレートの初期画面が表示されるはずです。
26-4 Web アプリの動かし方(初回の準備)
Section titled “26-4 Web アプリの動かし方(初回の準備)”Web アプリは Windows フォームと違って、「Web サーバー にアクセスして使う」ものです。 本研修では、その Web サーバーも Visual Studio が自動で用意・起動 してくれます。 初回だけ少し癖があるので、ここでまとめて確認しておきます。
別の Web サーバーをインストールする必要はない
Section titled “別の Web サーバーをインストールする必要はない”「Web アプリ」と聞くと Apache や IIS のような Web サーバーを別途インストールするイメージがあるかもしれませんが、本研修では不要 です。
.NET 8 には Kestrel(ケストレル) という小さな Web サーバーが組み込まれており、Visual Studio が F5 を押したタイミングで起動してくれます。
F5 を押す ↓Visual Studio がプロジェクトをビルド ↓Kestrel(.NET 内蔵 Web サーバー)を起動 ↓ブラウザが自動で開く ↓プロジェクトの起動 URL が表示される実務でアプリをサーバーに公開するときは、IIS や Linux 上の Nginx と組み合わせるパターンがありますが、研修中は意識しなくて OK です。
初回起動時:HTTPS 開発証明書の信頼
Section titled “初回起動時:HTTPS 開発証明書の信頼”ASP.NET Core MVC は、起動時に https://localhost:xxxx/ で動こうとします(xxxx は数字)。
HTTPS を使うためには、ローカル PC に 開発用の SSL 証明書 が必要です。
初回 F5 のときに、次のような確認ダイアログが順に出ることがあります。
| ダイアログ | 出る場所 | 選ぶ答え |
|---|---|---|
| ASP.NET Core が開発用 SSL 証明書を作成しました。信頼しますか? | Visual Studio | はい |
| この証明書をインストールしますか?(Windows のセキュリティ警告) | Windows | はい |
この操作は、研修環境で 1 回だけ やればその後は出てきません。
ブラウザによっては、起動後にも「セキュリティ警告」のような画面が出ることがあります。 そのときは「詳細設定」 → 「このまま続行」のような選択で進めて OK です(開発用のため)。
起動 URL とポート番号
Section titled “起動 URL とポート番号”Visual Studio がブラウザで開く URL は次のような形です。
https://localhost:7XXX/http://localhost:5XXX/7XXX や 5XXX の数字部分は ポート番号 といい、プロジェクト作成時に Visual Studio が決めて、Properties/launchSettings.json に書き込みます。
プロジェクトごとに違うので、別のプロジェクトを起動したら URL も変わります。
Ch26_MvcFortuneApp → https://localhost:7123/別のプロジェクト → https://localhost:7456/URL のポート番号は 研修中は深く意識しなくて OK です。「ブラウザが自動で開く URL を使う」とだけ覚えておけば足ります。
補足:
localhostとは
localhostは「自分自身の PC」を意味する特別な名前です。 ブラウザは「自分の PC で動いている Kestrel」にアクセスして、その応答を画面に表示しています。 他人の PC からはアクセスできません。
Web サーバーを止める方法
Section titled “Web サーバーを止める方法”ブラウザのタブを閉じても、Web サーバー(Kestrel)は裏で動いたまま になります(ブラウザは「画面を見る道具」にすぎないため)。 止めるには、Visual Studio 側で操作します。
| やりたいこと | 操作 |
|---|---|
| デバッグ実行を止める | Visual Studio の「停止」ボタン(赤い四角)、または Shift + F5 |
| ブラウザだけ閉じる | ブラウザのタブを × で閉じる(サーバーは止まらない) |
止め忘れると、Visual Studio が「すでに実行中なので F5 が押せない」状態になります。 そのときは 「停止」ボタンを押してから F5 で再起動します。
コードを変更したらどうなる?
Section titled “コードを変更したらどうなる?”| 変更箇所 | 必要な操作 |
|---|---|
View(.cshtml) | 保存して ブラウザでリロード(F5 または Ctrl + R) だけで反映 |
Controller(.cs) | Visual Studio で ホットリロード ボタン、または デバッグ停止 → F5 で再実行 |
Model(.cs) | 同上(Controller と同じ) |
View はテキストファイルに近い扱いなので、ブラウザのリロードだけで変更が見えます。 Controller・Model は C# のコードなので、再ビルドが必要です(ホットリロードが効くこともあります)。
ホットリロードとは
Visual Studio 2022 には、デバッグ実行中にコードを変更しても ビルドし直さずに反映する 機能があります(炎のアイコン)。 効くケースと効かないケースがあるので、迷ったら「停止 → F5」で問題ありません。
ファイアウォール警告が出たら
Section titled “ファイアウォール警告が出たら”初回 F5 のときに、Windows ファイアウォールから「このアプリのネットワーク通信を許可しますか?」というダイアログが出ることがあります。
| 設定項目 | チェック |
|---|---|
| プライベートネットワーク | ✅(チェックを入れる) |
| パブリックネットワーク | ⬜(チェックを外す) |
その後「アクセスを許可する」を選んでください。 研修環境では自分の PC 内でしか使わないため、これで十分です。
ここまでをまとめると
Section titled “ここまでをまとめると”ASP.NET Core MVC アプリの実行 ↓Visual Studio で F5 を押すだけ ↓裏側で Kestrel(Web サーバー)が起動 ↓ブラウザが自動で開く ↓止めるときは Visual Studio の停止ボタンか Shift+F5「Web アプリは別のサーバーを立てる必要がある」というイメージを持っていた人もいるかもしれませんが、研修中の体験範囲では Visual Studio だけで完結 します。
実務でサーバーに公開する手順はもっと複雑ですが、本研修の範囲外です。 動かす仕組みが分かっていれば、後で公開手順を学んだときも理解が早くなります。
26-5 プロジェクト構成を確認する
Section titled “26-5 プロジェクト構成を確認する”プロジェクトを作ると、研修の他の章と同じ 「ソリューションフォルダの中にプロジェクトフォルダ」 という階層になります(主要なものだけ抜粋)。
Chapter26/ ← ソリューションフォルダ├─ Chapter26.sln└─ Ch26_MvcFortuneApp/ ← プロジェクトフォルダ ├─ Controllers/ │ └─ HomeController.cs ├─ Models/ ├─ Views/ │ ├─ Home/ │ │ ├─ Index.cshtml │ │ └─ Privacy.cshtml │ └─ Shared/ │ └─ _Layout.cshtml ├─ wwwroot/ ← CSS・JavaScript・画像 ├─ Properties/ │ └─ launchSettings.json ← 起動 URL・ポート番号などの設定 ├─ Program.cs ← アプリ起動の入口 ├─ appsettings.json ← 設定情報 └─ Ch26_MvcFortuneApp.csproj ← プロジェクトファイル(Nullable 設定もここ)| フォルダ・ファイル | 役割 |
|---|---|
| Controllers | Controller クラスを置く |
| Models | Model クラスを置く |
| Views | 画面表示の .cshtml を置く(Controller 名のフォルダで整理) |
| wwwroot | CSS・JS・画像など、ブラウザに直接送る静的ファイル |
| Properties/launchSettings.json | F5 実行時に開く URL・ポート番号(本研修ではほぼ触らない) |
| Program.cs | アプリ起動時の設定(本研修ではほぼ触らない) |
| appsettings.json | 接続文字列などの設定値(第 27 章以降で使う) |
| Ch26_MvcFortuneApp.csproj | プロジェクト設定。Nullable disable はここで変更 |
この章では、Controllers・Models・Views の 3 つだけを意識すれば OK です。
ソリューションフォルダ階層は第 1 章以降の他の章(コンソールアプリ・Windows フォーム)と同じなので、混乱しないよう注意してください。
26-6 最初から動いている部分を読み解く
Section titled “26-6 最初から動いている部分を読み解く”Controllers/HomeController.cs は、テンプレートが最初から用意している Controller です。
中を覗くと、次のような Index メソッドがあります。
public class HomeController : Controller{ public IActionResult Index() { return View(); } // ... (他のメソッド)}これだけのコードで、https://localhost:xxxx/ を開いたときに Views/Home/Index.cshtml が表示されています。
処理の流れ:
ブラウザで / にアクセス ↓ASP.NET Core が URL を見て「Home コントローラーの Index アクション」と判断 ↓HomeController.Index() が呼ばれる ↓return View() で対応する View を返す ↓Views/Home/Index.cshtml の内容が HTML として送られる ↓ブラウザに画面が表示されるURL と Controller・Action・View の対応:
| URL | Controller | Action | View |
|---|---|---|---|
/ | HomeController | Index() | Views/Home/Index.cshtml |
/Home/Index | HomeController | Index() | Views/Home/Index.cshtml |
/Home/Privacy | HomeController | Privacy() | Views/Home/Privacy.cshtml |
「URL の /Xxx/Yyy が、XxxController の Yyy() メソッドに対応する」 ── これが ASP.NET Core MVC の基本ルールです。
.cshtml はブラウザに届かない ── サーバーで HTML に変わる
Section titled “.cshtml はブラウザに届かない ── サーバーで HTML に変わる”ここで、Web アプリを理解するうえで いちばん大事なポイント を押さえます。
.cshtml ファイルは、書いたまま そのままブラウザに送られるわけではありません。次の順で動きます。
.cshtml(HTML + @… + asp-…) ↓ サーバー(ASP.NET Core)が処理する @… や asp-… を実行して、ふつうの HTML に組み立てる ↓できあがった「素の HTML」だけがブラウザに届くつまり、@ や asp- といった記号はサーバーの中で消化され、ブラウザには一切届きません。ブラウザが受け取るのは、<h1> や <input> だけでできた、ごくふつうの HTML です。
自分の目で確かめる:ページのソースを表示
F5 で動かして画面を開き、ブラウザで 右クリック → 「ページのソースを表示」(または
Ctrl + U)してみてください。.cshtmlに書いたはずの@modelやasp-forは どこにもなく、素の HTML(<input name="...">など)になっているはずです。「自分が書いたファイル」と「ブラウザが受け取る HTML」は別物だ、と体感できます。
この「サーバーで HTML を組み立ててから送る」という仕組みが分かると、
- なぜ HTML の中に C#(
@)を書けるのか(→ 送る前にサーバーで実行されるから) - なぜ
asp-forのような独自の属性が使えるのか(→ サーバーが素の HTML に変換してくれるから)
がすっきり理解できます。asp-for が実際にどんな HTML に変わるかは、入力フォームを作る 26-9 で具体的に見ます。
26-7 Home 画面の View を改造してみる
Section titled “26-7 Home 画面の View を改造してみる”まず、テンプレートが用意した View を 少し書き換えて みます。 View を変えると画面表示が変わることを体感するのが目的です。
Views/Home/Index.cshtml を開いて、全体を次のように書き換えてください。
@{ ViewData["Title"] = "占いアプリ トップ";}
<h1>占いアプリへようこそ</h1>
<p>この画面は、HomeController の Index アクションが返している View です。</p><p>これから、入力フォームを持つ占い画面を作ります。</p>
<p><a asp-controller="Fortune" asp-action="Index" class="btn btn-primary">占いを始める</a></p><a asp-controller="Fortune" asp-action="Index"> は、まだ存在しない FortuneController の Index アクションへのリンクです。今はクリックするとエラーになりますが、後で FortuneController を作るとここから飛べるようになります。
F5 で実行(または変更を保存してブラウザをリロード)し、画面が変わることを確認してください。
ここで分かること:
- View を編集すると、画面表示がそのまま変わる(C# コードのビルドは不要なことが多い)
- View は HTML がベース(
<h1>、<p>などのタグがそのまま使える) @{ ... }の中には C# コードが書ける(Razor 構文)
26-8 占いアプリの全体像
Section titled “26-8 占いアプリの全体像”ここから、占いアプリを作っていきます。 これが「Model・View・Controller の 3 役そろい踏み」を体験する小さなアプリになります。
アプリの動作:
1. ブラウザで /Fortune/Index を開く → 名前・生年月日・今日の気分の入力フォームが表示される
2. 入力して「占う」ボタンを押す → /Fortune/Result に POST 送信される → ラッキーカラー・ラッキーナンバー・今日の一言が表示される
3. 結果画面の「もう一度占う」リンクで /Fortune/Index に戻る作るもの(4 つ):
| 種類 | ファイル | 役割 |
|---|---|---|
| Model | Models/FortuneViewModel.cs | 入力された値と占い結果を持つ |
| Controller | Controllers/FortuneController.cs | GET で入力画面、POST で結果画面 |
| View(入力) | Views/Fortune/Index.cshtml | 入力フォーム |
| View(結果) | Views/Fortune/Result.cshtml | 占い結果 |
この 4 つを、3 つのステップに分けて、各ステップでブラウザで動かして確かめながら 作っていきます。いきなり全部を書くのではなく、動くものを少しずつ育てる のがコツです。
| ステップ | 作る/足すもの | 動かして確かめること |
|---|---|---|
| Step1(26-9) | Model + Controller の Index(GET)+ 入力 View | 入力フォームが表示される |
| Step2(26-10) | Controller の Result(POST)+ 結果 View | 入力した値が結果画面に渡る(Model Binding) |
| Step3(26-11) | Result に占いロジック(ランダム)を足す | ラッキーカラー等が表示される |
入力画面と結果画面が分かれているのがポイント
第 19〜25 章の Windows フォームでは「1 つのフォームの上で値が変わる」スタイルでした。 Web では 画面ごとに別の URL・別の View にするのが自然です。 このやり方に慣れると、画面遷移の多い業務アプリも組みやすくなります。
26-9 Step1:入力画面を表示する
Section titled “26-9 Step1:入力画面を表示する”まず「ブラウザで入力フォームが表示される」ところまで作ります。必要なのは データの入れ物(Model)・入口の Index(GET)・入力 View の 3 つです。占うボタンの処理(POST)は Step2 で足すので、ここでは作りません。
Model を作る:FortuneViewModel.cs
Section titled “Model を作る:FortuneViewModel.cs”Models フォルダの上で 右クリック → 追加 → クラス で、新しいクラスを追加します。
名前は FortuneViewModel.cs にしてください。
namespace Ch26_MvcFortuneApp.Models;
public class FortuneViewModel{ // 入力(入力画面で使う) public string UserName { get; set; } = ""; public DateTime? BirthDate { get; set; } public string Mood { get; set; } = "";
// 結果(結果画面で使う) public string LuckyColor { get; set; } = ""; public int LuckyNumber { get; set; } public string Comment { get; set; } = "";}これは、第 7・10 章で学んだ普通の C# クラスです。 入力 3 項目と結果 3 項目をまとめて持つ、シンプルな データの入れ物 です。
| プロパティ | 意味 |
|---|---|
UserName | 入力された名前 |
BirthDate | 入力された生年月日(未入力なら null) |
Mood | 選んだ気分(「元気」「普通」「疲れ気味」のいずれか) |
LuckyColor | 占い結果のラッキーカラー |
LuckyNumber | 占い結果のラッキーナンバー |
Comment | 占い結果の今日の一言 |
「ViewModel」という名前
名前の末尾に
ViewModelが付いていますが、これは 「View で使うことを意図した Model」、言いかえると 画面に必要な値をまとめて持つ入れ物 という意味の慣習名です。中身は普通の C# クラスなので、特別な仕掛けはありません。この章の
FortuneViewModelは、入力 3 項目(UserName・BirthDate・Mood)と結果 3 項目(LuckyColor・LuckyNumber・Comment)を 1 つにまとめています。第 29 章 では、検索条件・部署の一覧・検索結果をまとめたEmployeeSearchViewModelが出てきます。「View に必要な値を 1 つにまとめておくと、画面側から 型付きで(@Model.プロパティで)アクセスでき、名前のタイプミスも減らせる」── この感覚をここでつかんでおくと、後の章が読みやすくなります。
DateTime?の?第 11 章で学んだ
Nullable<T>の省略形です。DateTime?はNullable<DateTime>と同じ意味で、「日付の値、または未設定(null)」を表せます。 入力画面の生年月日欄を空のまま送信されたときにnullとして受け取れるように、DateTime?にしています。
Controller を作る(まずは Index だけ)
Section titled “Controller を作る(まずは Index だけ)”Controllers フォルダの上で 右クリック → 追加 → コントローラー → 「MVC コントローラー - 空」 を選び、名前を FortuneController.cs にします。
(慣れていれば「右クリック → 追加 → クラス」で空のクラスを作って、: Controller を自分で書いても構いません。)
Step1 では、入力画面を返す Index(GET)だけを書きます。占う処理は Step2 で足します。
using Microsoft.AspNetCore.Mvc;using Ch26_MvcFortuneApp.Models;
namespace Ch26_MvcFortuneApp.Controllers;
public class FortuneController : Controller{ [HttpGet] public IActionResult Index() { FortuneViewModel model = new FortuneViewModel(); return View(model); }}ここでのポイント:
: Controller(継承):Controller親クラスを 継承(第 13 章)することで、Web の機能(View()メソッドなど)が使えます。[HttpGet] Index():ブラウザで/Fortune/Indexを開いたときに呼ばれ、空のFortuneViewModelを作って入力 View に渡します。Result(POST)と占いロジックは Step2・Step3 で足します。「画面を見るときは GET、送るときは POST」という分け方は Step2 で詳しく扱います。
入力 View を作る:Views/Fortune/Index.cshtml
Section titled “入力 View を作る:Views/Fortune/Index.cshtml”View を置くには、まず Views フォルダの中に Fortune フォルダ を作ります(Controller 名と同じ名前)。
Views/├─ Home/├─ Shared/└─ Fortune/ ← 新規作成 ├─ Index.cshtml ← この後作る(入力画面) └─ Result.cshtml ← その次に作る(結果画面)その中に、右クリック → 追加 → 新しい項目 → Razor ビュー - 空 を選んで、Index.cshtml を作ります。
@model Ch26_MvcFortuneApp.Models.FortuneViewModel
@{ ViewData["Title"] = "今日の占い";}
<h1>今日の占い</h1>
<p>名前と生年月日、今日の気分を入力して「占う」を押してください。</p>
<form asp-controller="Fortune" asp-action="Result" method="post"> <div class="mb-3"> <label for="UserName" class="form-label">名前</label> <input asp-for="UserName" class="form-control" /> </div>
<div class="mb-3"> <label for="BirthDate" class="form-label">生年月日</label> <input asp-for="BirthDate" type="date" class="form-control" /> </div>
<div class="mb-3"> <label for="Mood" class="form-label">今日の気分</label> <select asp-for="Mood" class="form-control"> <option value="">選んでください</option> <option value="元気">元気</option> <option value="普通">普通</option> <option value="疲れ気味">疲れ気味</option> </select> </div>
<button type="submit" class="btn btn-primary">占う</button></form>各部分の意味を見ていきます。
@model ...(先頭)
Section titled “@model ...(先頭)”@model Ch26_MvcFortuneApp.Models.FortuneViewModelこの View が どの型の Model を受け取るか を宣言します。
これにより、ファイル内の Model という変数が FortuneViewModel として扱われます。
<form asp-controller="Fortune" asp-action="Result" method="post">
Section titled “<form asp-controller="Fortune" asp-action="Result" method="post">”入力フォームのタグです。 属性で「送信先は Fortune コントローラーの Result アクション、メソッドは POST」と指定しています。
| 属性 | 意味 |
|---|---|
asp-controller="Fortune" | 送信先の Controller |
asp-action="Result" | 送信先のアクション |
method="post" | POST で送る(GET だと URL に値が付く) |
<input asp-for="UserName" /> などの入力部品
Section titled “<input asp-for="UserName" /> などの入力部品”asp-for="UserName" は、この入力欄を Model の UserName プロパティに対応 させる指定です。
これがあるおかげで、フォーム送信時に model.UserName に値が自動で入ります(Model Binding)。
| 入力タグ | 対応プロパティ | 入力タイプ |
|---|---|---|
<input asp-for="UserName" /> | model.UserName | 文字列 |
<input asp-for="BirthDate" type="date" /> | model.BirthDate | 日付ピッカー |
<select asp-for="Mood"> | model.Mood | ドロップダウン |
<select> の <option value="元気">元気</option> のように、value 属性で送信される値を指定できます。
asp-for は何に変わる?(サーバーが生成する HTML)
Section titled “asp-for は何に変わる?(サーバーが生成する HTML)”asp-for="UserName" は、サーバーで処理されると次のような 素の HTML に変わってからブラウザに届きます(26-6 で見た「.cshtml はそのまま送られない」の具体例です)。
<!-- View に書くと(.cshtml) --><input asp-for="UserName" class="form-control" />
<!-- ブラウザが受け取る HTML(サーバーが生成) --><input class="form-control" type="text" id="UserName" name="UserName" />ポイントは、asp-for="UserName" が name="UserName" を自動で付けてくれる ことです。
この name="UserName" こそが、送信されたときに model.UserName へ値を届けるための名札 になります(次の 26-10 Model Binding)。
asp-for="UserName" → name="UserName" → model.UserName に届く(View に書く) (ブラウザに届く HTML) (Controller で受け取る)「asp-for は、Model のプロパティ名から入力欄の name を作ってくれる部品」と捉えると、入力 → Model Binding までが 1 本の線でつながります。
HTML タグの読み方(事前学習の復習)
<form>は入力欄のまとまり、<input>は 1 つの入力欄、<select>はドロップダウン、<label>は項目名のラベルです。事前に学習した HTML の復習として、ここで思い出しておきましょう。
class="..."は Bootstrap の見た目
form-control/btn btn-primary/mb-3などのclassは Bootstrap(見た目を整える仕組み)のクラスです。付けると入力欄やボタンが整って見える だけで、動作には影響しません。中身の仕組みは気にしなくて OK です(一覧は 26-12 の早見表参照)。
ここで動かす(1 回目・Step1 完了)
F5で実行し、/Fortune/Indexを開いてください。入力フォームが表示されれば Step1 は成功 です。 ※この時点で「占う」を押すと、まだResultを作っていないのでエラーになります(Step2 で作ります)。26-7 で作ったトップ画面の「占いを始める」リンクからも、この入力画面に来られるようになりました。
26-10 Step2:入力した値が結果画面に渡るのを確かめる(Model Binding)
Section titled “26-10 Step2:入力した値が結果画面に渡るのを確かめる(Model Binding)”次に「占うボタンで送った入力が、結果画面に表示される」ところまで作ります。ここでは 占いのランダムはまだ足しません。まず「入力がサーバーに届く」ことだけを確かめます。
Controller に Result(POST)を足す
Section titled “Controller に Result(POST)を足す”FortuneController の Index メソッドの下に、Result メソッドを足します。
[HttpPost]public IActionResult Result(FortuneViewModel model){ // まずは入力をそのまま結果画面に渡すだけ(占いは Step3 で足す) return View(model);}| メソッド | いつ呼ばれる? | 返す View |
|---|---|---|
[HttpGet] Index() | ブラウザで /Fortune/Index を直接開いたとき | Views/Fortune/Index.cshtml |
[HttpPost] Result(...) | 入力フォームで「占う」を押したとき | Views/Fortune/Result.cshtml |
「画面を見るときは Index(GET)」「フォーム送信して結果を出すときは Result(POST)」と役割を分けています。
return View()とreturn View(model)の違いController の最後でよく書く
return View(...)には、2 つの形があります。
return View()… 対応する View を表示する。Model は渡さない(View 側で@Modelを使わない画面向き。26-6 のHomeController.Index()がこの形)。return View(model)… 対応する View を表示し、同時に Model を渡す。View 側では@Model.プロパティで受け取れる(この章のIndex・Resultはこちら)。どちらも「自分のアクション名と同じ名前の View」を探します(
Index()ならViews/Fortune/Index.cshtml)。別の View を表示したいときはreturn View("Result", model)のように View 名を明示 することもできますが、本研修では基本の 2 形だけ覚えれば十分です。なお、「View を返す」以外に、別のアクションへ送り直す
return RedirectToAction("Index")という返し方もあります。登録・更新・削除のあとに一覧画面へ戻すときに使い、第 30 章 で扱います(この章では使いません)。
Model Binding:入力が引数に届くしくみ
フォームに入力された値は、自動的に 同じ名前の引数プロパティ(
model.UserNameなど)に詰められてResult(model)に届きます。この自動マッピングを Model Binding と呼びます。橋渡しのカギは、入力欄の名前(asp-for)と引数プロパティの名前が一致していること です。
第 10 章で学んだメソッドの引数が、ここでは「フォームから来た値の受け取り口」になっています。名前さえ合っていれば、値は自動で運ばれてきます。
実際に「占う」を押してから値が届くまでの 時系列の流れ(ブラウザ → Model Binding → Controller)は、26-13「処理の流れを 2 つに分けて理解する」 の POST シーケンス図で確認できます。
補足:Model Binding と Model
ここで「Model Binding」と「Model」の関係を整理しておきます。
- Model Binding は、ブラウザから送られてきた値を、Controller のアクションの引数に自動で入れる仕組み です。
- アクションの引数は、
stringやintのような 単純な型 でも受け取れます(Result(string userName)と書けばuserNameに値が入ります)。- 一方、
FortuneViewModelのような クラス型 で受け取ると、フォームの入力値が そのクラスの各プロパティ(UserName・BirthDate・Mood)に自動で入ります。入力欄が多いときは、引数を 1 つずつ並べるより、まとめて受け取れるクラス型のほうが便利です。- そしてこの章の
FortuneViewModelは、入力値を受け取る役割(POST でResult(model)に届く)と、結果画面へ表示する値を渡す役割(return View(model)で View に渡す)の 両方 を 1 つで担っています。だから入力 3 項目と結果 3 項目を 1 つのクラスにまとめてあるのです(26-9 の定義を見返してみてください)。
結果 View を作る(まず入力の確認だけ):Views/Fortune/Result.cshtml
Section titled “結果 View を作る(まず入力の確認だけ):Views/Fortune/Result.cshtml”Views/Fortune フォルダの中に、Result.cshtml を Razor ビュー - 空 で追加します。Step2 ではまず 入力された値だけ を表示します(占い結果は Step3 で足します)。
@model Ch26_MvcFortuneApp.Models.FortuneViewModel
@{ ViewData["Title"] = "占い結果";}
<h1>占い結果</h1>
<div class="alert alert-info"> <p><strong>@Model.UserName さんの今日の運勢</strong></p>
@if (Model.BirthDate.HasValue) { <p>生年月日: @Model.BirthDate.Value.ToString("yyyy年M月d日")</p> }
<p>今の気分: @Model.Mood</p></div>
<p> <a asp-controller="Fortune" asp-action="Index" class="btn btn-secondary">もう一度占う</a></p>ポイント:
@Model.UserNameのように書くと、Controller から渡った Model の値が HTML に埋め込まれます。@if (Model.BirthDate.HasValue)は Razor の条件分岐で、「生年月日が入力されていれば表示」しています。<a asp-controller="Fortune" asp-action="Index">は入力画面へ戻る GET リンクです。
ここで動かす(2 回目・Step2 完了)
F5→/Fortune/Indexで入力 → 「占う」。結果画面に名前・気分・(入れていれば)生年月日が出れば成功 です。 これで「入力した値がサーバーの Controller に届き(Model Binding)、結果画面まで渡っている」ことが確認できました。まだラッキー結果は出ません(Step3 で足します)。
26-11 Step3:占いの結果(ランダム)を足す
Section titled “26-11 Step3:占いの結果(ランダム)を足す”最後に、ランダムな占い結果(ラッキーカラー・ナンバー・一言)を足して完成させます。
Controller に占いロジックを足す
Section titled “Controller に占いロジックを足す”FortuneController に色の候補 LuckyColors と MakeComment を足し、Result を次のように書き換えます。
using Microsoft.AspNetCore.Mvc;using Ch26_MvcFortuneApp.Models;
namespace Ch26_MvcFortuneApp.Controllers;
public class FortuneController : Controller{ private static readonly string[] LuckyColors = { "赤", "青", "緑", "黄", "紫", "白", "黒", "ピンク", "オレンジ" };
[HttpGet] public IActionResult Index() { FortuneViewModel model = new FortuneViewModel(); return View(model); }
[HttpPost] public IActionResult Result(FortuneViewModel model) { Random random = Random.Shared; model.LuckyColor = LuckyColors[random.Next(LuckyColors.Length)]; model.LuckyNumber = random.Next(1, 100); model.Comment = MakeComment(model.Mood, random); return View(model); }
private string MakeComment(string mood, Random random) { string[] candidates; switch (mood) { case "元気": candidates = new[] { "今日はあなたのエネルギーが周りに伝わる日です。", "新しいことに挑戦すると、思った以上にうまくいきそうです。" }; break; case "普通": candidates = new[] { "焦らず一歩ずつ進めば、思わぬ発見がある一日に。", "落ち着いた行動が、良い結果につながります。" }; break; case "疲れ気味": candidates = new[] { "今日は無理せず、自分を大切にする一日に。", "ゆっくり休むことが、明日への力になります。" }; break; default: candidates = new[] { "今日も一日、自分らしく。" }; break; } return candidates[random.Next(candidates.Length)]; }}
static readonlyとRandom.Shared色の候補は変わらない固定値なので
static readonlyで 1 つだけ用意し、全リクエストで共有します(第 8 章)。Randomもnew Random()を毎回作らず、.NET 共有のRandom.Sharedを使います。new Random()を短時間に連続生成すると内部のシード(乱数の元)が重複して同じ結果が続くことがありますが、Random.Sharedならその心配がありません。
結果 View に占い結果を足す
Section titled “結果 View に占い結果を足す”Result.cshtml の <div class="alert alert-info"> の中、「今の気分」の段落の下に、次を足します。
<hr />
<ul> <li>ラッキーカラー: <strong>@Model.LuckyColor</strong></li> <li>ラッキーナンバー: <strong>@Model.LuckyNumber</strong></li> <li>今日の一言: @Model.Comment</li> </ul>ここで動かす(3 回目・完成)
F5→/Fortune/Indexで入力 → 「占う」。ラッキーカラー・ナンバー・一言が表示されれば占いアプリ完成 です。同じ入力で何度か占うと、結果が毎回変わります(Random)。 「もう一度占う」で入力画面(GET)に戻ります。アドレスバーに/Fortune/Resultを直接入れると エラー(POST 限定) になることも確かめてみましょう。
26-12 MVC の「おまじない」早見表
Section titled “26-12 MVC の「おまじない」早見表”ここまでで @model・asp-for・class="..." など、「こう書くと動く決まり」 がいくつも出てきました。これらは MVC やフレームワークの お約束(おまじない) で、いまは 「何をするものか(役割)」だけ分かれば十分 です。仕組みの中身は、後で必要になったときに深掘りすれば大丈夫。
迷ったらこの表に戻ってきてください(第 27 章以降でも参照します)。
| おまじない | 何をするもの(役割) |
|---|---|
@model 型名(View 先頭) | この View が受け取るデータの型を宣言する |
@Model.プロパティ | Controller から渡された値を画面に表示する |
@{ ... } / @if (...) { ... } | View(HTML)の中に C# を書く(Razor 構文) |
asp-controller="Fortune" | リンク / フォームの送信先の Controller を指定 |
asp-action="Result" | 送信先のアクションを指定 |
asp-for="UserName" | 入力欄を Model の UserName と結びつける(Model Binding の橋渡し) |
[HttpGet] / [HttpPost] | そのアクションを GET / POST のどちらで呼ぶか |
: Controller(継承) | Web 用の機能(View() など)を使えるようにする |
class="btn btn-primary" 等 | Bootstrap の見た目クラス。付けると整って見える(中身は気にしなくてよい) |
builder.Services.AddControllersWithViews()(Program.cs) | 「MVC を使う」という起動時のお決まり |
app.MapControllerRoute(...)(Program.cs) | URL と Controller / Action の対応づけの規定(/Xxx/Yyy → XxxController.Yyy()) |
「おまじない」と「ブラックボックス」は違う
めざすのは「役割は一言で言えるが、内部実装は今は受け入れる」状態です。完全に無視するのではなく、「これは〇〇する決まり」と言えるようにしておきましょう。後の章のコメント課題でも、おまじないは「何をする決まりか」を一言だけ書きます。
26-13 処理の流れを 2 つに分けて理解する
Section titled “26-13 処理の流れを 2 つに分けて理解する”ここがこの章で 最も大切な部分 です。
URL と Controller / View の対応(占いアプリ)
Section titled “URL と Controller / View の対応(占いアプリ)”まず、占いアプリの 2 つの URL が、どのメソッド・どの View につながるかを 1 本の線で追ってみます(各メソッドが「いつ呼ばれるか」は 26-10 の表も参照)。
/Fortune/Index → FortuneController の Index() が呼ばれる → return View(model) → Views/Fortune/Index.cshtml が使われる
/Fortune/Result → FortuneController の Result(model) が呼ばれる → return View(model) → Views/Fortune/Result.cshtml が使われるView ファイルに直接アクセスしているわけではありません
ブラウザがリクエストを送る先は、あくまで Controller の Action です。
Index.cshtmlやResult.cshtmlを URL で直接開いているのではなく、Controller が「どの View を使うか」を選んで、組み立てた HTML を返しています。 だから/Fortune/Index.cshtmlのような URL は存在しません。URL に書くのは/コントローラー名/アクション名だけです。
この「URL → Controller のアクション → View」という流れを、次に GET と POST の 2 パターンで詳しく見ます。
GET の流れ(入力画面を表示するとき)
Section titled “GET の流れ(入力画面を表示するとき)”- ブラウザは URL を GET で開く(アドレスバー入力やリンククリック)
- Controller は
[HttpGet]のIndex()が呼ばれる - 空の
FortuneViewModelを作って、Views/Fortune/Index.cshtmlに渡す - View が入力フォームの HTML を組み立ててブラウザに返す
POST の流れ(占い結果を表示するとき)
Section titled “POST の流れ(占い結果を表示するとき)”- ブラウザは「占う」ボタンで POST 送信する(フォームに入力された値が一緒に送られる)
- ASP.NET Core が Model Binding で値を
FortuneViewModelに詰める - Controller は
[HttpPost]のResult(model)が呼ばれる Randomで結果 3 項目を model に追加し、Views/Fortune/Result.cshtmlに渡す- View が占い結果の HTML を組み立ててブラウザに返す
入力画面と結果画面は別の URL・別の View で、ボタン押下のタイミングで POST 送信されて切り替わる ── この流れを覚えてください。
GET も POST も、ブラウザが話しかける先は同じ
FortuneControllerです2 つの図で「呼ばれる相手」が違うように見えないように注意してください。どちらも、裏では ASP.NET Core がルーティング(と POST のときは Model Binding)を済ませてから、
FortuneControllerのアクションを呼びます。 あなたが実装するのは、どちらの場合も Controller のアクション です。 GET と POST で変わるのは、HTTP メソッド(GET / POST) と、それによって呼ばれる アクション(Index/Result) だけで、「呼び先のクラスを変える」必要はありません([HttpGet]/[HttpPost]の属性で振り分けます)。
26-14 GET と POST の違い
Section titled “26-14 GET と POST の違い”| 観点 | GET | POST |
|---|---|---|
| 主な用途 | 画面を 見る(取得する) | データを 送る(更新する) |
| 値の渡し方 | URL に付く(?name=山田二郎) | リクエスト本体に含まれる |
| ブックマーク | できる | できない(URL に値がない) |
| 何度繰り返しても OK? | OK(同じ画面が返るだけ) | 注意(送信が複数回起こる可能性) |
| 例 | 画面表示、検索結果ページの URL | フォーム送信、ログイン、占い結果生成 |
「見るだけは GET、送るときは POST」と覚えれば、ほぼ大丈夫です。
ブラウザのアドレスバーは GET
ブラウザのアドレスバーに URL を入れて Enter を押すと、必ず GET リクエストになります。 フォームの送信ボタンを押したときだけ、HTML の
<form method="post">指定によって POST になります。 このため、POST だけ呼ばれる処理は、アドレスバーから直接は実行できません。
/Fortune/Resultをアドレスバーに直接入れたらどうなる?エラー(
HTTP 405 Method Not Allowed)になります。Resultは[HttpPost]限定のアクションなので、GET ではアクセスできないためです。 「結果は必ずフォーム送信から作る」というルールが、属性で表現されています。
よく出る HTTP ステータス(最小限)
Section titled “よく出る HTTP ステータス(最小限)”Web アプリでは、うまくいかないときに HTTP ステータス という番号でエラーの種類が返ります。次の 3 つだけ知っておくと、第 27 章以降のトラブル対応がぐっと楽になります。
| 状態 | 意味 | よくある原因 |
|---|---|---|
| 404 Not Found | URL に対応する処理がない | Controller 名・Action 名・URL の打ち間違い |
| 405 Method Not Allowed | URL はあるが GET / POST が違う | [HttpPost] のアクションに GET でアクセスした(上の /Fortune/Result の直打ちがこれ) |
| 500 Internal Server Error | サーバー側で例外が起きた | C# コードの例外、View のエラー |
番号を覚えておくと、画面がエラーページになったときに「これは URL の間違い(404)か」「メソッド違い(405)か」「コード側の例外(500)か」と 当たりを付けられます。第 27 章以降で DB に接続すると 500 に出会いやすくなるので、ここで顔だけ覚えておきましょう。
26-15 Windows フォームアプリとの比較
Section titled “26-15 Windows フォームアプリとの比較”第 19 章の SimpleCalc(Forms)と、この章の占いアプリの構造を並べてみます。
| 観点 | Windows フォーム(SimpleCalc) | Web(占いアプリ) |
|---|---|---|
| 入力部品 | TextBox・ComboBox | <input>・<select> |
| 実行のきっかけ | ボタン Click イベント | フォーム POST 送信 |
| 処理を書く場所 | Button_Click メソッド | [HttpPost] Result(model) |
| 入力値の取得 | nameTextBox.Text | model.UserName(Model Binding) |
| 結果の表示先 | 別ラベルの Text プロパティ | Model.LuckyColor を View に渡す |
| 画面遷移 | 同じフォームで値が変わる | 入力画面と結果画面で URL が変わる |
「入力 → 処理 → 出力」という流れは同じです。 ただし、処理が走る場所 が違います。
| 種類 | 処理が走る場所 |
|---|---|
| Windows フォーム | 利用者の PC 上(クライアントのみ) |
| Web アプリ | サーバー上(あなたが用意するサーバー)+ ブラウザ |
Web ではブラウザに HTML を「送り直す」ことで画面が切り替わります。 Windows フォームのように「同じ画面の表示だけ更新する」とは仕組みが違うことを意識してください。
Web は「1 回ごとに作り直す」── 前の状態は覚えていない
Windows フォームは、アプリが起動している間ずっと
TextBoxやフィールドに値が 残り続けます。 一方 Web は 1 リクエストごとに独立 しています。サーバーは前のリクエストのことを基本的に覚えておらず、リクエストが来るたびに Controller が動いて HTML を 一から組み立てて返し、返したら忘れます。 だから「入力した値を次の画面でも使いたい」ときは、フォームで もう一度サーバーに送る(POST)必要があります。占いアプリで入力画面と結果画面が分かれていて、結果が POST 送信で作られるのも、この「毎回送って作り直す」仕組みに沿っているからです。
よくあるつまずき
Section titled “よくあるつまずき”| つまずき | 原因 | 対応 |
|---|---|---|
| 「ASP.NET Core Web アプリ」テンプレートが見つからない | 必要なワークロードが入っていない | Visual Studio Installer で「ASP.NET と Web 開発」をインストール |
| 実行してもブラウザが起動しない | Visual Studio の起動設定 | 「IIS Express」または「プロジェクト名」で起動するように選ぶ |
/Fortune/Index にアクセスすると 404 | Controller の名前または View の場所が違う | FortuneController + Views/Fortune/Index.cshtml を確認 |
入力した値が model.UserName に入らない | asp-for="UserName" の名前が違う | プロパティ名と完全一致させる(大文字小文字も) |
<select> で選んだ気分が model.Mood に入らない | <option value="..."> の値が指定されていない | <option value="元気">元気</option> のように value を明示 |
占い結果画面で @Model が null エラー | 結果画面に直接 GET でアクセスしている | 必ず入力画面から「占う」ボタンで POST 送信して開く |
| 結果が毎回同じ | new Random() を短時間に複数回作るとシードが重複することがある | 本文どおり Random.Shared を使う(共有インスタンスなのでシード重複の心配がない) |
@Model.BirthDate.Value で例外 | BirthDate が null のまま | Model.BirthDate.HasValue で先にチェック |
| 「アクセス権がない」と HTTPS 警告 | 開発用証明書 | Visual Studio が自動で扱うので、警告を許可 |
学んだことチェック
Section titled “学んだことチェック”- ブラウザとサーバーがリクエスト/レスポンスでやり取りすることを説明できる
- Visual Studio の F5 で Web サーバー(Kestrel)が自動起動することを説明できる
- 別途 Web サーバーをインストール不要なことを説明できる
- Web サーバーを止める方法(VS の停止ボタン)を覚えている
- MVC の Model・View・Controller それぞれの役割を説明できる
- URL とコントローラー・アクションの対応(
/Xxx/Yyy→XxxController.Yyy())を説明できる - ブラウザは View ファイルを直接開くのではなく、Controller のアクションにリクエストし Controller が View を選ぶ、と説明できる
-
return View()とreturn View(model)の違いを説明できる - GET と POST の違いを 2 つ以上挙げられる
-
[HttpGet]と[HttpPost]でアクションを使い分けられることを説明できる - Model Binding の概要(フォーム入力 → Controller の引数)を説明できる
- 入力画面と結果画面を別の View に分けるメリットを説明できる
- View の
@modelと@Model.プロパティを読み解ける -
.cshtmlがサーバーで HTML に変換されてからブラウザに届くこと(@/asp-は届かない)を説明できる -
asp-for="UserName"がname="UserName"を生成し、それが Model Binding の名札になることを説明できる - アクション引数は単純型(
string/int)でもクラス型でも受け取れ、FortuneViewModelが入力と結果の両方の役割を持つことを説明できる -
asp-for・asp-controller・asp-actionの役割を 1 つずつ説明できる - 404 / 405 / 500 のおおまかな意味を説明できる
- Windows フォームとの違い(処理が走る場所、画面遷移)を説明できる
研修の進め方によっては、隣の人またはチーム内で説明確認を行います。
次の内容を、自分の言葉で説明してください。
- リクエストとレスポンスとは何ですか。
- MVC の Controller・Model・View はそれぞれ何を担当しますか。
- URL
/Fortune/Indexは、どのファイルのどのメソッドに対応しますか。 - ブラウザで URL を直接開いたときと、フォームを送信したときで、何が違いますか。
- なぜ
Index(GET)とResult(POST)で別のメソッドにしているのですか。 - フォームに入れた値が
model.UserNameなどに届く仕組みは何と呼ばれますか。 - View の
@model行は何のために書きますか。 - Windows フォームと Web アプリで、画面遷移の仕組みはどう違いますか。
この章の演習課題に取り組みます。
本章では、第 4〜15 章のコンソール課題と同じ タイマー方式 で進めます。次の 3 段階で取り組んでください。
| 段階 | 時間 | 内容 |
|---|---|---|
| ① 準備 | 10 分(目安) | 上の「ペア確認」と、必須課題(仕様)の読み込み。ペアや講師に質問してよい |
| ② ソロ作業 | 30 分(タイマーで計測) | 一人で必須課題に取り組む。タイマーが鳴ったら、完成・未完成にかかわらず作業を止めて提出する |
| ③ チーム時間 | 講師が指定する発表開始時刻まで | チーム内で 教え合い(分かった人が詰まった人に説明)とコードレビューを行い、発表者を決める。発展課題や実装の続行も可。時間配分はチームで管理する |
評価対象はタイマー時点で提出されたコードです(タイマー後に書き足した分は評価には含まれません)。 発表開始時刻は厳守 です。チーム時間中も、その時刻が来たら全員手を止めて発表に移ります。
必須課題の土台は先に作っておきます
必須課題は「本文 26-8〜26-11 で完成させた占いアプリに 年齢の表示を追加する」課題です。 占いアプリ本体(Model・Controller・View 2 つ)は本文どおり コピーで作って構いません(Web 1 日目で初出が多いため、ここは評価の主眼ではありません)。 ソロ作業のタイマーで測るのは、そこに自力で足す年齢計算 です。本文には完成コードを載せていないので、方針を見ながら自分で組み立てます。
演習の進め方の詳細は、付録A「演習の進め方」 を参照してください。
この章の演習の進め方
Section titled “この章の演習の進め方”課題はソリューション Kadai26 の中に作成してください。課題ごとに別のプロジェクトを作成 し、指定されたプロジェクト名を使います。
| 課題 | 必須/発展 | プロジェクト名 | 内容 |
|---|---|---|---|
| 課題26-1 | 必須 | Kd26_01_MvcFortuneApp | 占いアプリ + 年齢の計算・表示 |
| 課題26-2 | 発展 | Kd26_02_MvcFortuneCustom | 占いの改造(文言・数字・時間帯の挨拶) |
| 課題26-3 | 発展 | (プロジェクト不要) | 処理の流れを自分の言葉でまとめる |
提出ルール(タイマー方式)
30 分のタイマーが鳴ったら手を止め、
git add→commit→pushを行います。評価対象はタイマー時点のコミットのみです(タイマー後の追加は評価外)。Git が使えないときは付録 C のコピー提出に従い、提出メモ.txtに「どこまで完成 / 詰まったポイント」を書きます。コミットメッセージの形式:
Chapter26 タイマー提出: <どこまで完成> / <詰まったポイント>例:
Chapter26 タイマー提出: 年齢計算まで完成 / 誕生日前後の境目で詰まった
タイマー後のチーム時間
発表開始時刻まで、教え合い(分かった人が詰まった人に説明)/ コードレビュー / 発表者選出 / 発展課題や実装続行(任意・評価外)。時間配分はチームの判断、発表開始時刻は厳守。
課題 26-1 占い結果に「年齢」を追加する
Section titled “課題 26-1 占い結果に「年齢」を追加する”本文 26-8 〜 26-11(Step1〜3)にそって占いアプリを完成させたら、結果画面に 年齢 を表示できるようにします。
生年月日(Model.BirthDate)と今日の日付(DateTime.Today)から年齢を計算して出します。ここがソロ作業(タイマー)の中心 です。本文に完成コードはないので、下の仕様と方針を手がかりに 自力で 実装してください。
前提(タイマー前・コピーOK)
- 本文どおり占いアプリが動いている(
/Fortune/Index→ 入力 → 「占う」で結果が出る)
ソロ作業でやること(仕様)
- 結果画面に
@Model.UserName さんの年齢: ○○歳のように年齢を表示する - 生年月日が
null(未入力)のときは年齢を表示しない - 月日まで考慮した正確な年齢にする(今年まだ誕生日が来ていなければ 1 引く)
実装方針(おすすめは ①)
| 方針 | 場所 | 特徴 |
|---|---|---|
① ViewModel に Age プロパティを追加 | FortuneViewModel.cs + Controller | 計算は Controller、表示は View(MVC の役割分担に沿う) |
| ② View で計算 | Result.cshtml の Razor 部分 | Controller を変えなくて済む |
考え方のヒント(コードは自分で組み立てる)
基本は「今年の年 − 生まれた年」です。そこから、今年まだ誕生日が来ていなければ 1 を引く という補正を入れます。「誕生日が来たか」は、今日の月・日と生年月日の月・日を比べて判断します(
DateTime.Todayの.Year/.Month/.Dayが使えます)。 生年月日がnullのときは計算せずに表示も出さないよう、先にModel.BirthDate.HasValueで分岐してください(.Valueで中身のDateTimeが取れます)。
確認すること
- 占いアプリが本文どおり動く(入力 → 占う → 結果)
- 生年月日を入れて占うと、年齢が正しく表示される(誕生日前後の境目も含む)
- 生年月日を空のままだと年齢欄が出ない
- Controller と View のどちらに計算ロジックを置いたか、自分で説明できる
- タイマー時点で commit(または
提出メモ.txt)を済ませた
発展課題はチーム時間に取り組みます(評価対象外・任意)。改造系は Kd26_02_MvcFortuneCustom として、必須課題のプロジェクトをコピーして実験すると安全です。
課題 26-2 占いを改造する
Section titled “課題 26-2 占いを改造する”占いアプリを、下から 1 つ以上 選んで改造してみましょう。
| 選択肢 | 内容 | ヒント |
|---|---|---|
| A:文言バリエーション追加 | 各気分の comments 配列を 4 つ以上に増やす | MakeComment の case を編集 |
| B:ラッキー数字を 100 〜 999 の範囲に | 3 桁の数字を出す | random.Next(100, 1000) |
| C:挨拶を時間帯で変える | 結果画面の冒頭を「おはよう/こんにちは/こんばんは」と切り替える | DateTime.Now.Hour で分岐。Controller で ViewBag.Greeting = "..." のように代入し、View で @ViewBag.Greeting と書くと表示できる(下記補足参照) |
補足:
ViewBagとは
ViewBagは、Controller から View に 「Model 以外の値をちょっと渡したい」 ときに使う仕組みです。本文 26-7 で使ったViewData["Title"]と中身はほぼ同じで、ViewBag.TitleとViewData["Title"]はどちらでも同じ値を指します。// Controller 側ViewBag.Greeting = "こんにちは";@* View 側 *@<p>@ViewBag.Greeting</p>Model にプロパティを増やすほどでもない小さな値(タイトル、メッセージ、フラグなど)を渡すときに便利です。 ただし「型がチェックされない」ため、業務コードでは Model に入れる方が安全で、
ViewBagは補助的に使う程度にとどめます。
確認すること
- 選んだ改造が正しく動く
- 改造を入れた場所を自分で指せる
課題 26-3 処理の流れを自分の言葉でまとめる
Section titled “課題 26-3 処理の流れを自分の言葉でまとめる”ここまでで作ったアプリを題材に、自分の言葉で処理の流れをまとめて ください。
提出形式
- 課題 26-1 のプロジェクト
Kd26_01_MvcFortuneAppの プロジェクト直下 に提出メモ.md(または提出メモ.txt)を作成 - 下記「まとめる観点」を見出しまたは番号付きで網羅
- 紙のノートに書いたものを写してもよい、ペアで口頭発表した内容を文字起こししてもよい
まとめる観点
- ブラウザで
/Fortune/Indexを開いたとき、何が起きて画面が表示されるか - 入力して「占う」を押したとき、サーバー側で何が起きるか
- Controller・Model・View が どのタイミングで何をしているか
- GET と POST はどう使い分けられているか
- Windows フォーム版(第 19 章 SimpleCalc)との違い
説明テンプレート(参考)
「/Fortune/Index を開くと、まずブラウザが ___ という GET リクエストを送ります。 サーバーは ___ を見て、FortuneController の ___ メソッドを呼びます。 そこで ___ が作られ、View に渡されて、___ が HTML として返ります。 ...」この課題はコードを書きません。 「コピーして動かしたコード」を「読めて、話せる」状態にする ことが目的です。 書いた内容は次回のペア確認・発表で使えるよう、自分の言葉で残しておくのがおすすめです。
提出前チェックリスト
Section titled “提出前チェックリスト”- ソリューション名が
Chapter26 - プロジェクト名が
Ch26_MvcFortuneApp - csproj が
<Nullable>disable</Nullable> -
Models/FortuneViewModel.csが作成されている -
Controllers/FortuneController.csに GETIndexと POSTResultがある -
Views/Fortune/Index.cshtml(入力画面)が作成されている -
Views/Fortune/Result.cshtml(結果画面)が作成されている -
/Fortune/Indexにアクセスして入力フォームが表示される - 入力して「占う」ボタンで結果画面に遷移する
- 「もう一度占う」で入力画面に戻る
- 課題 26-1 で年齢が正しく表示される(未入力なら年齢欄なし)
- タイマー時点で commit(または
提出メモ.txt)を済ませた - (発展 26-2 を実施した場合)選んだ改造が動く
-
bin・obj・.vsフォルダが Git 管理に入っていない - 開発用 HTTPS 証明書ファイルなど機密物がコミットされていない
Git への提出
Section titled “Git への提出”git statusgit add .git commit -m "Chapter26 タイマー提出: <どこまで完成> / <詰まったポイント>"git push origin mainGit の詳しい操作は、付録 C「Git のインストールと提出ルール」 を参照してください。
この章のまとめ
Section titled “この章のまとめ”- Web アプリは、ブラウザとサーバーの リクエスト/レスポンス で動く
- F5 を押すと Visual Studio が内蔵 Web サーバー(Kestrel)を自動起動 する(別途 Web サーバー不要)
- 初回は HTTPS 開発証明書 を信頼する必要がある(以降は不要)
- 止めるには Visual Studio の停止ボタン(または
Shift + F5) - MVC は、Web アプリの中身を Model・View・Controller の 3 役に分ける考え方
- ASP.NET Core MVC の URL ルール:
/Xxx/YyyはXxxController.Yyy()に対応。ブラウザは View ファイルを直接開くのではなく、Controller のアクションにリクエストし、Controller が View を選ぶ - 画面ごとに 別のアクション・別の View を用意するのが Web アプリの基本
return View()は Model を渡さず、return View(model)は Model を渡して@Model.XXXで表示できる- うまくいかないときは 404(URL 違い)・405(GET/POST 違い)・500(コード側の例外) で当たりを付ける
- フォーム入力は Model Binding で自動的に Controller の引数に届く
- View は HTML + Razor 構文(
@model、@Model.XXX、@ifなど) .cshtmlは サーバーで素の HTML に変換されてから ブラウザに届く(@やasp-はブラウザには行かない)。asp-for="UserName"はname="UserName"を生成し、それが Model Binding の名札になるasp-for・asp-controller・asp-actionで、Model と画面の対応を宣言できる[HttpGet]と[HttpPost]で、同じ URL でも別のメソッドを呼べる(/Fortune/Index と /Fortune/Result のように URL を変えてもよい)- Windows フォーム編との違いは「処理が走る場所」(PC かサーバーか)と「画面遷移」(同じ画面が更新されるか別画面が返るか)
- 本章はゼロから組むことより、動かして観察し、説明できる ことを優先
次章では、もう一歩 MVC に踏み込み、MVC アプリから SQLServer のデータベースを扱う 方法を学びます。
占いアプリではデータベースを使わず、Controller の中で結果を作っていました。
第 27 章からは、第 16 章で作った TrainingDB の employees テーブル に Web アプリから接続し、Web 版の社員管理アプリを作っていきます。
第 23〜25 章の Windows フォーム社員管理アプリを そのまま Web 上で動かす イメージです。 画面の作り方や認証方式(Web では SQL 認証)は変わりますが、「画面 → Controller → DB → 画面」 という流れは Windows フォームと共通の発想で読み解けます。