JavaエンジニアがASP.NET Coreを触ってみた

# はじめに
### このテーマで投稿しようと思ったきっかけ
単純に仕事で.NETのスキルが必要になったからである。
筆者はエンジニア歴のうち半分以上はJava案件(10年くらい？)に関わってきた。
Javaと.NETはほぼほぼ似ている(≒？)と言われますが、コーディング部分において実際にどのくらいJava(主にSpringBoot)の経験が活かせ、何が違うのかが気になったので、実際に.NETを触ってみようと思った。
もし、同様のことを気になったエンジニアがいたら参考になれば幸いである。

### 軽く.NETとは
.NETは説明不要なほど人気な言語なのでざっと要約すると以下のような特徴がある。
- Webアプリケーションの開発が容易
- 複数のプログラミング言語に対応(C#, VB.NETなど)
- 開発コストを抑えられる
- クロスプラットフォームに対応(Windows, Mac, Linux)

最後のクロスプラットフォームに対応は筆者にとって驚きだった。
2000年代はWindowsしか使えませんでした。ところが2016年ごろから.NET Coreがリリースされてから急激に進化した模様。(全然追ってなかった・・・)
開発手法も以下のように定義されてる。
- 昔ながらの**MVCモデル**
- 今やASP.NETの基本**Razorページ**
- 新時代の開発手法**Blazor**

## 軽く環境構築から
### まずはスペック
というわけで軽く環境構築してみようと思います。ちなみに今回は以下のような環境で整えてみようと思う。
- OS: MacOS Ventura(13)
- Visual Studio Code
- .NET Core6.0(当時のLTS)

ちなみにMacにもVisual Studioがあるが2024年夏にサポート終了するようなので今回はVisual Studio Codeで整えてみる。

### インストールや諸々
- [.NET 6.0のダウンロード](https://dotnet.microsoft.com/ja-jp/download/dotnet/6.0)

    インストールしたらまずターミナルで`dotnet`コマンドを通す。

    ```
    ln -s /usr/local/share/dotnet/dotnet /usr/local/bin/
    ```
    `dotnet` コマンドを用いてインストール状態を確認
    
    ```
  $ dotnet --version
  > 6.0.417
  $ dotnet --list-sdks
  > 6.0.417
  $ dotnet --list-runtimes
  > Microsoft.AspNetCore.App 6.0.25
  > Microsoft.NETCore.App 6.0.25
    ```
<br>

 - VSCodeのインストール
     [公式サイト](https://code.visualstudio.com/download)からインストールして展開するだけ。
     VSCodeをインストールしたら`C#` のプラグインをVSCodeのマーケットプレイスからインストールしてください。
     ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618351/7d08e786-bf2f-a537-4a9f-04b5b9da1ffc.png)
     必須ではありませんがコマンドパレット(command+shit+p)で以下のプラグインを入れておくと便利です。

     - デバッグ

        - `Download .Net Core Debugger`
     - `code` コマンド

        - `Install 'code' command in PATH`

## Razorアプリを作ってみる
### 記事のテーマの意図、検証したいこと
ここで記事のテーマになるんですが、Javaに慣れすぎたエンジニアが.NETが必要になったらどれだけ違和感なく溶け込むことができるのか？全く新しく覚える必要がある要素は何か？をRazorアプリを作りながら整理したいと思います。

### Razorページプロジェクトを作成
VisualStudioCodeのターミナル`dotnet`コマンドを使ってRazorページプロジェクトを作成します。
作成したプロジェクトを`code` コマンドを使って開きます。

```
dotnet new webapp -o FirstRazorApp
code FirstRazorApp
```

VisualStudioCodeが起動し、プロジェクトを開く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618351/8c7c51ba-5ec1-10d7-9d01-18200fd2f402.png)

VisualStudioCodeのターミナルを開き、`dotnet run`を実行。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618351/efce5cfa-3a2e-9ef8-37e9-7607f786a16c.png)

`http://localhost:5075` を実行しすると画面が開けることが確認できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618351/a4260738-2f28-71fc-d890-2509bb7e82ba.png)


### プロジェクト構成

<table>
  <thead>
    <tr>
      <th colspan="2">構成</th> <th>説明</th>
    </tr>
  </thead>
  <tr>
    <td colspan="2">Pagesフォルダ </td> <td>ページ関連のファイルを配置。</td>　
  </tr>
  <tr>
    <td> </td> <td>Sharedフォルダ</td> <td>画面レイアウトやエラーメッセージ画面など共通画面レイアウトを配置</td>
  </tr>
  <tr>
    <td colspan="2">Propertiesフォルダ </td> <td>ランチャの設定など</td>
  </tr>
  <tr>
    <td colspan="2">wwwrootフォルダ </td> <td>ページが参照するリソースを配置</td>
  </tr>
  <tr>
    <td colspan="2">Program.cs </td> <td>プロジェクトを起動するときの最初に実行するプログラム<br>SpringBoot
    でいうSpringBootApplication.javaような</td>
  </tr>
</table>

| 拡張子 | 説明 |
|:-:|:-:|
| .cshtml  | テンプレートファイル  |
| .cshtml.cs  | Modelクラス  |


### Razorページの利用

入力フォームRazorページを新規作成し、画面を表示するまで実装してみる。
`dotnet new page -n {名前} -o {場所} -p:n {名前空間}` を使ってpageを生成する。

```
dotnet new page -n InputForm -o Pages -p:n FirstRazorApp
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618351/e76c7427-5d80-9cba-ca49-3a1a4e6921d8.png)

ここから簡単な入力フォームを書いていく。まずはモデルクラス。

```InputForm.cshtml.cs
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace MyApp.Namespace
{
    public enum Genders
    {
        male,
        female
    }

    public enum PlatformItems
    {
        Windows,
        macOS,
        Linux,
        ChromeOS,
        Android,
        iOS
    }

    public class InputFormModel : PageModel
    {
        [BindProperty(SupportsGet = true)]      // クエリパラメータとバインド
        public int Id {get; set;}

        public string? Message {get; set;}      // 型の後に?をつけるとNull許容型で宣言
        [DataType(DataType.Text)]
        public string? Name {get; set;}
        [DataType(DataType.EmailAddress)]
        public string? Mail {get; set;}
        [DataType(DataType.PhoneNumber)]
        public string? TelNumber {get; set;}
        public bool CheckBox {get; set;}
        public Genders Gender {get; set;}
        public PlatformItems Platform {get; set;}

        public void OnGet()
        {
            Message = "何か入力してみて！";
        }

        // Post処理時、同名の変数にフィールドの入力値をそれぞれバインドされる。
        public void OnPost(int id, string name, string mail, string telNumber, bool checkbox, 
            string gender, PlatformItems platform)
        {
            Message = string.Format("[Id: {0}, Name: {1}, Mail: {2}, Tel: {3}, CheckBox: {4}, Gender: {5}, Platform: {6}]", 
                id, name, mail, telNumber, checkbox, gender, platform);
        }
    }
}
```
コードを書いてみたけど以下の２点におっ？と反応。

- `public string? Message {get; set;}`　の型の後ろに`?`にあるのは？
- 変数名の命名

型の後ろに`?`を付けるのはNull許容型の宣言を指す。.NETでは変数宣時にNull許容を定義するのでコンパイル時にヌルポが発生する可能性のある変数に対して警告が発生し検出しやすくなった。
Javaではそのような仕組みはなく`NullPointerException` が発生した際の犯人探しに結構苦労したことは良い思い出だが、Javaと親和性の高いKotolinでは.NETと同様にヌルポ思想は実現している。
変数名のjavaでは頭文字が小文字から始まるに対して.NETでは頭文字が大文字から始まっている。
他にも`import`句が`using`であったり、JavaではDIを`アノテーション`で定義するの対して、.NETでは`[]`で定義するなど若干違ってたりするが、コーディングに関して大きく違和感を感じることもなかった。

では、続いてテンプレートファイル。
```InputForm.cshtml
@page "{id?}"
@model MyApp.Namespace.InputFormModel
@{

}

<div>
    <h1 class="dispaly-4">Welcome</h1>
    <p class="h4">@Model.Message</p>
    @using (Html.BeginForm())
    {
        <div class="form-group">
            @Html.DisplayName("Id")
            @Html.LabelFor(model => model.Id)
        </div>
        <div class="form-group">
            @Html.DisplayName("Name")
            @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control"} })
        </div>
        <div class="form-group">
            @Html.DisplayName("Mail")
            @Html.TextBoxFor(model => model.Mail, @Model.Mail, new { @class = "form-control" })
        </div>
        <div class="form-group">
            @Html.DisplayName("TelNumber")
            @Html.TextBoxFor(model=>model.TelNumber, new { @class = "form-control" })
        </div>
        <div class="form-group">
            <label class="form-label h5">
                @Html.CheckBoxFor(model => model.CheckBox, new { @class = "form-check-input"})
                @Html.DisplayName("CheckBox1")
            </label>
        </div>
        <div class="form-group">
            <label class="form-label h5">
                @Html.RadioButtonFor(model => model.Gender, MyApp.Namespace.Genders.male,  
                    new { @class = "form-check-input"})
                @Html.DisplayName("male")
            </label>
        </div>
        <div class="form-group">
            <label class="form-label h5">
                @Html.RadioButtonFor(model => model.Gender, MyApp.Namespace.Genders.female,  
                    new { @class = "form-check-input"})
                @Html.DisplayName("female")
            </label>
        </div>
        <div class="form-group">
            <label class="form-label h5">
                @Html.DisplayName("Platform")
                @Html.DropDownListFor(model => model.Platform, 
                    new SelectList(Enum.GetValues(typeof(MyApp.Namespace.PlatformItems))), 
                    new { @class = "form-control"})
            </label>
        </div>
        <input type="submit" class="btn btn-primary" value="送信">
    }
</div>

```

テンプレートファイルはモデルクラスとテンプレートファイルとバインドが可能であったりとSpringBootのテンプレートエンジンであるThymeleafほぼ似通ってるのであまり違和感は感じることもなかった。
ちなみにコンパイルすると以下のような画面に仕上がる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618351/b84fcb66-022a-e1a5-918b-4c432ae1726d.png)

入力して「送信」すると。。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618351/b2cab3ad-14df-a2b8-7231-c49fc1827eac.png)

入力した内容を表示するまでができた。
今回はここまでで。。。

## あとがき

Javaエンジニアが実際に.NETで開発環境構築+簡単なWebアプリを実装するまで学習してみたところの感想
- ヌルポ防止策に.NETでは変数宣言時にNull許容を定義するんで活用方法についてもう少し深掘りが必要。
- 変数名の命名が異なるので.NETのお作法を覚える必要があるのと使い分けられる慣れが必要。
- Razorアプリ≒SpringBoot？でほぼほぼSpringBootじゃん。

SpringBootの開発経験があればそんなに遜色なく.NETでも通じそうな印象。
尚、今回はBlazorアプリやNuGetやスキャフォールディングなどDB系は触れなかったが、今後の学習のテーマに。。。
ここまでの学習時間は６時間程度。

ここまで読んでいただいてありがとうございました。以上。

## 参考文献
- [ASP.NET Core入門 .NET対応](https://www.shuwasystem.co.jp/book/9784798069012.html)