IISにASP.NET8.0を配備する-Javaから見た.NET

# はじめに
Java 開発者が IIS で ASP.NET を使う時に考慮することをまとめました。

# 背景
とある .NET 8.0 で作られたアプリを使う為、環境構築と配備だけを行う機会がありました。
何も問題が無ければそれで終わりなのですが、トラブルでハマってしまうと、結局は自分で調べて解決する必要に迫られます。
Java で WEB アプリを使った経験があれば、対比していくことで、理解が早いと思います。
調べた過程で気が付いた事を記載します。

# .NET Framework と .NET(無印またはCore)
この２つは、IIS にとっては大きく扱いが異なります。
この区別が出来ていないと、この先を読んでいただいても正しく理解できないと思います。

ちゃんと区別して解説していないサイトが多いので混乱を招くことが多いです。

```mermaid
graph TD;
id1[.NET Framework 3.5] --マルチプラットホーム化--> id2[.NET Core] --> id3[".NET 5.0～(9.0)"]
id1-->id4[.NET Framework 4.8].->id3
```

.NET(無印)は、Windows 以外の OS でも動く、マルチプラットホーム対応になっています。
それに対して、**.NET Framework** は Windows のみで動く従来からあるものです。
この２つが今でも併存して使われています。

ここでは、**.NET 8.0** を対象にしています。(Framework ではありません)

# .NET 8.0 のインストール
先に.NET には２つあると書きましたが、.NET Framework は Windows Update で自動更新されますが、.NET(無印)は手動でインストールする必要があります。

https://dotnet.microsoft.com/ja-jp/download/dotnet/8.0

いろいろありますが、IIS で動かす為には、ASP.NET Core ランタイムで、**Hosting Bundle** が必要です。下の画像の黒い太文字を読んでいただくと解ります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3834038/25661434-3211-28c0-4ed0-9ee069a840eb.jpeg" width="60%">

:::note info
Hosting Bundle は、Java で言えば Apache とWEBコンテナをつなぐ AJP のような役割と思えば腑に落ちます。(仕組みは全然違いますが)
ASP.NET Core モジュール (ANCM)と呼ばれています。
:::

動かすだけなら、SDK は不要ですが、入れておくとツールが使えて便利です。

:::note warn
Visual Studio を使う場合は、SDK のバージョンに気を付けてください。
新しすぎる .NET のバージョンでは Visual Studio でビルドがエラーになる場合があります。
適合するバージョンを確認してください。
:::

# Visual Studio 2022 で ASP.NET アプリを作成する
.NET 8.0 を使うには、Visual Stdio は最新にアップデートしておく必要があります。
必要なら、**Visual Stdio Installer** を起動して**更新**してください。

Visual Studio を起動し、プロジェクトを作成します。
ここでは一番簡単な「ASP.NET Core Webアプリ」を選択します。

![WEBアプリ1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3834038/8dce7fb2-6575-902f-4802-917937f52bd0.jpeg)

:::note warn
他のプロジェクト(MVCモデル等)でもかまいませんが、**Framework** が付いたものは対象外です。
:::

プロジェクトが作成され展開されたら、「デバッグ」-「実行」(もしくは http(s)ボタン)を押します。
何も問題が無ければ、勝手にブラウザが立ち上がって下図の様な表示になります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3834038/0f9a1a95-42b8-81de-92c4-8c3cf40e75de.jpeg" width="75%">

:::note info
**https** がデフォルトですが、意味が無いので **http** としています。
:::

少し説明を省きましたが、コンパイル(ビルド)して、デバッグを実行したところです。

:::note warn
うまく動かない場合があります。
その時は、インストールされている .NET SDK のバージョンを確認してください。
Visual Studio でも .NET SDK がインストールされますが、手動でも SDK をインストールすると、コンパイル時に新しいバージョンを見てしまうので、不一致が発生します。
:::

# IIS に配備(デプロイ)する
ここからが本題です。
Java であれば、war ファイルを作成しますが、そこは Visual Studio の「**発行**」操作で行います。

![発行メニュー3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3834038/d7ccdef6-7905-f0a3-8819-15e03bcd91db.jpeg)

書き出す場所(IIS が読み取る場所にもなる)を指定します。
どこでも良いですが、ここでは、C:/web/app1 としました。
さらに、「**発行**」ボタンを押すと、その場所に書き出されます。
Java での war ファイルというより、ディレクトリ構造のまま複数の構成ファイルが書き出されます。

:::note info
書き出したフォルダのセキュリティ(権限)が気になります。
IIS のサービスのアカウントを確認すると、**ローカルシステムアカウント**なので問題は無いようです。
:::

# IIS のインストールと設定
IIS(Express) の Windows10/11 でのインストールは、
「**コントロールパネル**」の「**プログラム**」から「**Windows の機能の有効化または無効化**」を開きます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3834038/f0d4d41c-ac7f-0f45-a989-68375e37cdfe.jpeg" width="50%">

「ASP.NET 4.8」は Framework なので不要に思えますが、邪魔にはならないので、入れておいたほうが良さそうです。(他に必要な物にも自動でチェックが付きます)

:::note warn
IISの構成を変更したりして再インストールを行うと、.NET Core のバンドルが、外れる事がありました。
その場合は、.NET Core ランタイム(Hosting Bundleあり)の修復(インストーラーの再実行)を行ってください。
:::

IISマネージャを立ち上げます。
先に Visual Studio で作成したアプリを動かす為の設定には、次の方法があります。
解り易いようにURLの指定例も付記します。

1. 「Default Web Site」にアプリを追加する (http://*hostname*/appname)
2. 「Default Web Site」に設定する (http://*hostname*/)
3. サイトを追加する (http://*hostname*:81/)

サイトを追加する場合、ポート(80番)は別にする必要があります。
なので、実運用には使えません。
複数のアプリを動かそうとするなら、1の方法になります。

## アプリケーションプールの追加

サイトおよびアプリには、アプリケーションプールが必要です。
アプリが動くプロセスを分ける事で、セキュリティを高める仕組みです。
仮想ディレクトリは共有する事も出来ますが、アプリは他と共有することができません。
デフォルトのアプリケーションプールを利用する事も出来ますが、複数アプリを使う前提であれば、アプリごとに単独で作る必要があります。

![アプリケーションプールの追加.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3834038/b629c45b-36aa-1069-cedc-14c257a64d9c.jpeg)

ASP.NET の場合は、CLRバージョンを**マネージドコードなし**にします。

::: note info
**マネージドコードなし**の意味が重要です。
これは、IIS がアプリケーションコンテナとしては働かない事を意味します。
**あり** を選んだ場合、IIS は、.NET Framework のコンテナとして働きます。
:::

.NET はマルチプラットホームで動きます。
という事は、極端に言ってしまうと、プロセス管理を除けば、管理コンソール上から見た IIS は http(Port 80)/https(port 443) を共通で使う為の単なるリバースプロキシとしての役割しか担わないことになります。

## WEBコンテナはどこに？
Java のWEB開発経験者ならそう思うかもしれません。
.NET の場合は、アプリに内包されています。

![サイトの追加1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3834038/85b6ca26-211d-4208-8353-229303f8a22b.jpeg)


現状２つのサーバーモジュールがあり、**Kestrel** と **IIS** ですが、IIS は Windows 環境だけでしか使えません。
内包する IIS は Web.config で設定するので、IIS管理コンソールでの設定は不要という事のようです。(**マネージドコードなし**の選択と同じ意味)

アプリごとにコンテナが起動するのは、リソースの無駄にも思えますが、軽量なWEBコンテナを内包する事は、極めて開発効率が良いと言えます。
Java EE とか、デバッグ環境を作るだけでも大変ですから。

## アプリケーションの追加 - 呼び出し方法その１

IISマネージャでサイトにアプリケーションを追加します。

![アプリケーションの追加2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3834038/c63aad67-6754-3be0-1757-4878d2c625b0.jpeg)

エイリアスは何でも良いです(URLの名前になる)。
アプリケーションプールに先ほど作成したものを指定します。
物理パスには、Visual Studio で作成した場所を指定します。
IIS を再起動して、ブラウザで http://*localhost*/app1 でアクセスすれば、

![IISapp1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3834038/41304cb7-eced-c48f-324f-a88fd8678308.jpeg)

と表示されます。
別のPCで、ファイアーウォールを許可してあれば、http://(hostname)/app1 でも表示されます。

## サイトに設定する - 呼び出し方法その２

サイトにアクセスした際、直接アプリを起動する方法です。
リダイレクトすれば良いだけなのであまりお勧めしませんが、やり方だけ説明します。

![アプリケーションの追加2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3834038/aac112b0-4d1e-46d4-5e88-fe52e6b92189.jpeg)

IISマネージャのサイトの「詳細」で物理パスを修正します。
さらに、アプリケーションプールのCLRバージョンを**マネージドコードなし**に変更します。
サイトを再起動します。
これで、http://(hostname)/ でアプリが表示されます。

## サイトを追加する - 呼び出し方法その３

テストで既存のサイトの設定を変更したくない場合には有効です。
WEBサイトの追加を選択します。

![サイトの追加2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3834038/795bce6b-d865-15c4-2e93-71293cfbdaae.jpeg)

サイト名は任意の名前。
複数のサイトで同じポート(80番)は使えないので、別のポート番号(この例では81)を割り当てる必要があります。
追加したら、アプリケーションプールも追加されているので、同じように設定します。
サイトを再起動し、http://*localhost*:81 で呼び出せば、アプリの画面が表示されます。

# 最後に

いかがでしたでしょうか。
「こんな簡単な事」と思っても以外と落とし穴が多いです。
「動けばいいや」で終わらせると後々応用が利かないので、理屈はちゃんと捉えておいたほうが良いと思います。
以降は、トラブルシューティングを載せておきます。

## トラブルシューティングその１
サイトやアプリの追加、削除を頻繁に行うと、おかしな挙動になることがあります。
(localhostだとinetpub/wwwrootが、ホスト名だとアプリ画面が表示される)
いったん、IIS を再インストールしようと、**無効化** した後再度 **有効化** しても直りません。
仕方ないので、無効化した後に、**Program Files** 配下の IIS ディレクトリと **inetpub** を削除してから **有効化** すると直りました。無効化しても、どこかに設定の内容が残るようです。

前にも書きましたが、IIS へのホスティングバンドルが、外れる事があります。
下記にリンクの記載にもあります。

https://learn.microsoft.com/ja-jp/aspnet/core/host-and-deploy/iis/hosting-bundle?view=aspnetcore-9.0

## トラブルシューティングその２
何も IIS に表示が出ない時に、配備したアプリが正しく動くのか確認したい場合があります。
コマンドプロンプトで配備したディレクトリに移って、そこにある、プロジェクト名.exe 実行します。

![アプリ確認1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3834038/0d179054-fc4d-ff46-bc8b-c47a6fbfa442.jpeg)


表示された URL でブラウザでアクセスするとアプリ画面が表示されるはずです。
WEBコンテナを内包しているから出来る技と言えます。
ここで正しく表示され、IIS の設定も間違っていないのに、IIS でアプリが表示されないなら、.NET Core ランタイムの修復(インストーラーの再実行)を行ってみてください。

## トラブルシューティングその３
呼び出し時に、time limit エラー(HTTP Error 500.37)が起こる場合。

![Error500_37.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3834038/21c42502-65ff-2dc4-fd45-033fa7531d5d.jpeg)

本当に処理が遅いだけであれば、web.config で時間を延ばす事は出来ます。
そうでない場合、アプリケーションプールの権限が不足している事が考えられます。

![アプリケーションプールのID.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3834038/20c3df61-d3d2-52d2-4d3c-37ee499682f2.jpeg)


https://learn.microsoft.com/ja-jp/iis/manage/configuring-security/application-pool-identities

デフォルトは一番権限の弱い、**ApplicationPoolIdentity** なので、このプールのプロセス内で動くアプリが他のリソースを参照しようとして権限が足りないと動きません。なるべく弱いほうが安全ですが、とりあえず、**LocalSystem** で動くか試すと良いでしょう。設定後、IIS の再起動は忘れずに行って下さい。