ASP.NET Core 3.0 Razor Pages 事始め(1) - はじめてのRazor Pagesアプリケーション


## 記事目次

1. [ASP.NET Core 3.0 Razor Pages 事始め(1) - はじめてのRazor Pagesアプリケーション](https://qiita.com/gushwell/items/6d8b801923b639d9ea2e) <-- この記事
2. [ASP.NET Core 3.0 Razor Pages 事始め(2) - スキャフォールディングとDBマイグレーション](https://qiita.com/gushwell/items/7eb76edf7006c0f02be4)
3. [ASP.NET Core 3.0 Razor Pages 事始め(3) - マイグレーションのやり直しとURLルーティング](https://qiita.com/gushwell/items/7ebe70f0d6adfd10ae12)
4. [ASP.NET Core 3.0 Razor Pages 事始め(4) - ページモデルとページハンドラ](https://qiita.com/gushwell/items/1deac26aaed945cc8631)
5. [ASP.NET Core 3.0 Razor Pages 事始め(5) - Postページハンドラとタグヘルパー](https://qiita.com/gushwell/items/daf901d4d76301dadea7)
6. [ASP.NET Core 3.0 Razor Pages 事始め(6) - データベースに初期値を設定する](https://qiita.com/gushwell/items/f7be44e668a6e168fc61)
7. [ASP.NET Core 3.0 Razor Pages 事始め(7) - Viewの変更とコンカレンシー例外処理](https://qiita.com/gushwell/items/913e8e95a0a79949af3c)
8. [ASP.NET Core 3.0 Razor Pages 事始め(8) - 検索機能の追加](https://qiita.com/gushwell/items/134930aba1d181100547)
9. [ASP.NET Core 3.0 Razor Pages 事始め(9) - ページに新しいフィールドを追加する](https://qiita.com/gushwell/items/a330e592f76efda13c42)
10. [ASP.NET Core 3.0 Razor Pages 事始め(10) - 検証機能の追加](https://qiita.com/gushwell/items/12e180ef129ea6a05757)


## はじめに

ASP.NET Coreから利用できるようになったRazor PagesによるWebアプリ開発についての学習の記録をここに残していこうと思います。

ASP.NET MVC (Coreではない)はこれまでに使っているので、ASP.NET MVCと比較してどうなのか、という視点で説明するような個所も出てくるかと思います。

まずは、公式ページの

[チュートリアル: ASP.NET Core で Razor ページ Web アプリを作成する](https://docs.microsoft.com/ja-jp/aspnet/core/tutorials/razor-pages/?view=aspnetcore-3.0)

の記事に沿って、チュートリアルをやっていこうと思います。このチュートリアルのページは日本語化されてるし、翻訳も良い出来なので、僕がここで書く意味はあるのか？という疑問は残りますが、あくまでも学習の記録ということでご容赦を。

チュートリアルには書かれていない内容とかも（もし、あれば）書ければと思っています。


## 準備

使うのは、Visual Studio Code  です。
C# for Visual Studio Code (最新バージョン) をインストールします。

それと、[.NET Core 3.0 SDK](https://dotnet.microsoft.com/download/dotnet-core/3.0)が必要です。これもインストールする必要があります。

僕は、Visual Studio 2019 v16.3 更新したら、.NET Core 3.0 SDKが入ったので、手動でのインストールはしていません。Visual Studio 2019 for Mac の場合は、v8.3以降に.NET Core 3.0 が含まれています。


ASP.NET Core Razor Page は、ASP.NET Coreで導入されたWebアプリケーションのフレームワークです。

チュートリアルやってみただけの感想ですが、ASP.NET MVCと似ている部分も多いので、ASP.NET MVCでの開発経験があれば、それなりにスムーズに学習できるかなと思います。まあ個人的な感想ですが。

## Razor Pages の特徴
Razor Pages の特徴は、ControllerとViewsフォルダがプロジェクトにありません。
この２つが、Pagesフォルダに統合されています。

Pagesフォルダの中に、ページファイル（.cshtml)と、それに対応する`<ページ名>.cshtml.cs` という名前の分離コードファイルがあります。例えば、index.cshtml の場合は、index.cshtml.cs ファイルがあります。

`<ページ名>.cshtml.cs`には、MVCで言うところのViewModel+Actionメソッドを定義します。

この前提を知っていると、チュートリアルもスムーズに理解できるかなと思います。

## Razor Pagesのプロジェクトを作成する


では、さっそく作成してみます。

1. VS Codeからターミナルウインドウを表示します。

2. cdコマンドで、プロジェクトを作成したい親ディレクトリに移動します。

    例えば、以下のようなコマンドを実行します。
    
    ```sh
    cd source/repos
    ```

3.  以下のコマンドを投入します。

    ```sh
    dotnet new webapp -o RazorPagesMovie
    ```

    これで、RazorPagesMovie フォルダーに新しい Razor Pages プロジェクトが作成されます。

4. 次に、下のコマンドを投入し、VS Code で、このフォルダを開きます。

    ```
    code -r RazorPagesMovie
    ```

    VS Codeは、現在のインスタンスのまま、RazorPagesMovie フォルダを開きます。

## プロジェクト構成

プロジェクトには、Pages フォルダとwwwroot フォルダーがあります。初期状態はいたってシンプルな構造です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29415/d63ec6dd-3f10-6cdf-3e91-041d40e71d2b.png" width=30%/>


Pagesフォルダには、`.cshtml` ファイルと `.cshtml.cs` ファイルがあります。View と それに対応するサーバー側のコードを書くファイルです。
ここがMVCとRazorPagesとの大きな違いのようです。

ASP.NET MVC と同様に、 Sharedフォルダの下には、_Layout.cshtml もあります。

wwwrootは、JavaScript ファイル、CSS ファイルなどの静的ファイルが格納されます。このフォルダ構造は、Content と Scriptsに分かれていたASP.NET MVC よりもいいですね。

そのほか、プロジェクトフォルダ直下には、`appSettings.json` `Program.cs` `Startup.cs` などがあります。

Controllerフォルダはありません。

## 実行してみる

Ctrl+F5キーで実行します。

環境を聞いてきた場合は、.NET Core を選択します。Launch.jsonが作成されます。再度、Ctrl+F5キーを押します。


すると、ブラウザが起動し初期ページが表示されます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29415/29b050ac-cea4-b78d-1248-92c9941edff0.png" width=60% />



画面上の privacy リンクをクリックすると、Privacyページに移動します。

## cshtml.cs ファイルをのぞいてみる

試しに、Privacyページに対応する Privacy.cshtml.csの中を覗いてみます。

```c#
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;

namespace RazorPagesMovie.Pages
{
    public class PrivacyModel : PageModel
    {
        private readonly ILogger<PrivacyModel> _logger;

        public PrivacyModel(ILogger<PrivacyModel> logger)
        {
            _logger = logger;
        }

        public void OnGet()
        {
        }
    }
}

```

とてもシンプルです。


### Razor ページ ハンドラー

PrivacyModelクラスには `OnGet`というメソッドはあるのが分かります。これが、Actionメソッドに対応するメソッドのようです。
名前のとおり、Http Get に対応するメソッドですね。

この  `OnGet` メソッドには、Actionメソッドと違い、戻り値がありません。
ページを返す場合は良いけど、ファイルを返したり、JSON返したりするのって、どうやるんだろう？という疑問は残りますが、通常のページ表示にかぎれば、コードはとてもシンプルです。

`OnPost`というメソッドを定義すれば、Http Post に対応するメソッドを定義できるようです。
MVCでは、属性を指定することで、Http Get、Http Post に対応していたのですが、Razor Pagesでは、メソッド名に代わっているようです。

これらのメソッドを **Razor ページ ハンドラー**と言うようです。




### PageModelクラス

上記のコードを見ると、`PrivacyModel` クラスは、`PageModel` クラスを継承していることが分かります。
`PageModel`から継承しているので、このクラスをページモデルと呼ぶようです。

`PageModel`クラスの定義をすこし覗いてみます。VS CodeもF12キーを押せば、該当のコードに飛べるので便利ですね。

```c#

namespace Microsoft.AspNetCore.Mvc.RazorPages
{
    [PageModel]
    public abstract class PageModel : IAsyncPageFilter, IFilterMetadata, IPageFilter
    {
        protected PageModel();

        public IUrlHelper Url { get; set; }
        public ITempDataDictionary TempData { get; set; }
        public RouteData RouteData { get; }
        public HttpResponse Response { get; }
        public HttpRequest Request { get; }
        [PageContext]
        public PageContext PageContext { get; set; }
        public ModelStateDictionary ModelState { get; }
        public IModelMetadataProvider MetadataProvider { get; set; }
        public HttpContext HttpContext { get; }
        public ClaimsPrincipal User { get; }
        public ViewDataDictionary ViewData { get; }

        
        ...
```

`HttpContext`、`Request`、`Response`、`ModelState`などのプロパティがあるのがわかります。
MVCのコントローラークラスと似ていますね。


なお、この`PageModel`クラスは、Razor構文を使って、cshtmlの中に記述することもできるようです。
小さなアプリケーションならば、それも良いでしょうが、普通は、分離コードファイル(.cshtml.cs)内に記述したほうが良いと思います。



## cshtml ファイルをのぞいてみる


Privacy.cshtmlの中も覗いてみます。

```html
@page
@model PrivacyModel
@{
    ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>

<p>Use this page to detail your site's privacy policy.</p>
```

先頭に`@page`ディレクティブがあります。これが、Razor Pagesアプリ用の .cshtmlファイルであることを示しています。
`@page`ディレクティブがあると、Controllerを経由せずに前述のページモデルが要求を処理しますよ、と印をつけていることになるようです。

次の行の`@model` ディレクティブで、この.cshtmlファイルが扱うモデルの型を指定します。
当然のことながら、ページモデルである`PrivacyModel`クラスがモデルになります。

3行目からの行では、`ViewData`ディクショナリに、値をセットしています。

```html
@{
     ViewData["Title"] = "Privacy Policy";
}
```

この`ViewData`は、継承元の`PageModel`クラスに定義されているプロパティですね。

この`ViewData["Title"]`の値は、直後の

```html
<h1>@ViewData["Title"]</h1>
```

で参照しています。

あとは、通常のhtmlと同じですね。

ちなみに、`Pages/Shared/_Layout.cshtml` がHTMLのページ全体を示すテンプレートファイルで、MVCと同じようです。

`_Layout.cshtml`の中に、`@RenderBody()` という行があり、これが、該当ページの.cshtml の内容に置き換わることになります。

ちょっと、Razor Pages のイメージが掴めたような気がします。チュートリアルの内容から脇にそれましたが、今日はこのへんで終わりにします。

次回は、モデルの追加をやります。