MS_Precompile - NetDevInfraWGinOSSConsortium/NetDevInfraWiki GitHub Wiki
ASP.NET のコンパイルには、6 個のモデルがある。
-
1 つの JIT コンパイル
-
5 つのプリコンパイル オプション
ASP.NET コンパイル ツール(Aspnet_compiler.exe)
このコンパイル モデルの説明とメリット・デメリットを下記に纏める。
補足(本ページの適用範囲/最新化): 本ページが扱う
Aspnet_compiler.exeによるプリコンパイルは、
.NET Framework 版の ASP.NET(Web Forms / MVC 5)専用である。
ASP.NET (System.Web) ASP.NET Core 既定の動作 .aspx/.cshtmlを実行時に JIT コンパイルビルド時にすべてコンパイル プリコンパイル ツール aspnet_compiler.exe不要(既定でコンパイル済み) ソースの配置 既定では必要 不要 初回応答の遅延 あり 原理的に無い つまり、ASP.NET Core では本ページの悩みは構造的に解消している
(dotnet publishした時点で.cshtmlも含めてコンパイル済み)。本ページは、既存の .NET Framework 版 ASP.NET の運用・移行判断の
ための記録として読むのが妥当である。なお、ASP.NET Core にも
Razor のランタイム コンパイル(AddRazorRuntimeCompilation)という
逆向きのオプションがあるが、これは開発時の利便のための機能で、
本番で有効にするものではない。
- 初期要求時に、JIT コンパイラによりコンパイルされる。
- アプリケーション内のファイルに変更を加えると、次回ページが要求されたとき、
変更されたファイルに対する依存関係を判断し、影響のあるファイルのみを、再び JIT コンパイルする。
以下のケースで有用。
- Web サイトを開発してテストする場合。
- 静的な情報を主とする Web サイトを対象とする場合。
- 頻繁な変更がない Web サイトを対象とする場合。
- 簡単に使用でき、初期応答以降は、応答速度に遅延が生じない。
-
初期要求時に JIT コンパイラによりコンパイルされるため、初期応答速度に遅延が生じる。
-
また、本番環境にソース コード ファイルを格納する必要があり、コード流出の可能性がある。
- 本番環境の管理者に参照されるケース
- Web サーバのセキュリティ ホールによりプログラム コードがダウンロードされるケース
- などを想定している。
移行メモ(用語): 本ページで言う「JIT コンパイル」は、
**CLR の JIT(IL → ネイティブ)ではなく、
ASP.NET の動的コンパイル(.aspx/.cs→ IL)**を指している
(.NETコンパイラ で言う 1 段目に相当)。
原文の文脈に従いそのまま「JIT コンパイル」と記載するが、
Microsoft の用語では **「動的コンパイル」**である。
補足(「コード流出」のリスクは限定的): 原文が挙げる
**「Web サーバのセキュリティ ホールによりプログラム コードが
ダウンロードされる」**という懸念について補足する。ASP.NET では、
.cs/.vb/.aspx.csなどのファイルは
HttpForbiddenHandlerによりブラウザからの直接要求が拒否される。
このため「URL を叩けばソースが落ちる」わけではない。現実的なリスクは、
- IIS のハンドラー マッピングの設定ミス(拡張子が静的ファイル扱いになる)
- ディレクトリ トラバーサルを許す別の脆弱性との組み合わせ
- 本番サーバの管理者・運用者が直接読む(原文の 1 点目)
であり、3 点目が最も現実的である。
知的財産の保護が目的なら、プリコンパイルに加えて
逆コンパイル・難読化 の検討も要る
(IL は容易に逆コンパイルできるため、
プリコンパイルだけでは保護として不十分)。
既定で、Web アプリケーションをコンパイルすると、
コンパイルされたコードは Temporary ASP.NET Files フォルダに配置される。
- ASP.NET の動的コンパイルの概要
https://learn.microsoft.com/ja-jp/previous-versions/aspnet/ms366723(v=vs.100)
-
ASP.NET コンパイル ツールを「-targetDir」スイッチを指定しないで実行することにより、
開発フォルダ内で Web アプリケーションを JIT コンパイルする。 -
これを本番環境に配置した後、アプリケーション内のファイルを直接変更した場合、
次回ページが要求されたとき、変更されたファイルに対する依存関係を判断し、
影響のあるファイルのみを、再び JIT コンパイルする。
以下のケースで有用である。
- 頻繁に変更される Web サイトを対象とする場合。
- 初期応答速度を短くする必要がある場合。
- 簡単に使用でき、応答速度に遅延が生じない。
- 本番環境にソース コード ファイルを格納する必要がある。
- また、アプリケーション内のファイルを変更した場合は、
JIT コンパイラによりコンパイルされるため、初期応答速度に遅延が生じる。
移行メモ(メリット欄の記載): 「本番環境にソース コード ファイルを
格納する必要がある」は、**メリットではなくデメリット(制約)**である
(-targetDirを指定しないため、ソースが残ったまま配置される)。
原文の記載を保ちつつ、この点を注記しておく。
- ASP.NET コンパイル ツールの「-u」スイッチを使用することにより、
ソース コードのみを DLL にコンパイルし、UI コード(「*.aspx」ファイルなど)は
更新できるように残すことができる。 - 本番環境に Web サイトを配置した後でも Web サイト全体を再コンパイルすることなく、
UI コードを変更できる。
- 簡単に使用でき、最初のページ要求時の応答時間を短くできる。
- Web サイト全体を再コンパイルすることなく、Web サイトの外観や動作を変更できる。
- プログラム コードという知的財産を保護できる。
- アプリケーションのすべての UI コード(*.aspx)を本番環境に格納する必要がある。
ASP.NET コンパイル ツールを「-u」スイッチを指定しないで実行することにより、
ソース コード・UI コードを DLL にコンパイルできる。
- 最初のページ要求時の応答時間を短くできる。
- ソース コード・UI コードという知的財産を保護できる。
- 配置前にコンパイルを個別に実行する必要がある。
- アプリケーションの UI に小さい変更を加えた場合でも、
Web サイト全体を再コンパイルする必要がある。
移行メモ(メリット欄の記載): 「配置前にコンパイルを個別に実行する
必要がある」も、メリットではなく制約である
(ビルド/配置の手順が 1 つ増える)。
補足(
-uの有無が実質的な分岐点): 5 つのオプションのうち、
実務上まず決めるのは **「-uを付けるか否か」**である。
-uあり(更新可能)-uなし(更新不可).aspxそのまま残る(差し替え可能) DLL に取り込まれる 初回応答 速い(コード部分は済んでいる) 最速 画面の小修正 ファイル差し替えで済む 全体を再ビルド・再配置 知的財産の保護 コードのみ コード + マークアップ 運用の統制 本番で直接いじれてしまう いじれない(=統制が効く) 「本番で
.aspxを直せる」ことは利点にも欠点にもなる。
緊急対応がしやすい反面、構成管理から外れた修正が本番に残る
という典型的な運用事故を招く。
統制を重視するなら-uなしを選ぶ。
-
ASP.NET コンパイル ツールのデフォルトの設定では、再コンパイルのたびアセンブリ名が変わる。
このため、1つのアセンブリを提供するためにアプリケーション全体を再配置する必要がある。 -
しかし「-fixednames」スイッチを指定して実行すると
アプリケーションの各ページに対して1つの固定名アセンブリを作成できる。
このため、変更したアセンブリのみ差分配置できる。
- アプリケーションに対して小さい更新を行う場合、他の方法より小さな更新で済む。
- アプリケーション内の各ページに対して1つのアセンブリが作成される。
- これにより、多くのページで構成されるサイトの場合、多くのアセンブリが生成される。
補足(差分配置は魅力的だが慎重に): 「変更したページの DLL だけ
差し替える」という運用は一見効率的だが、次の副作用がある。
- ページ数だけ DLL が増える(数百ページなら数百ファイル)
→ アプリケーション起動時のアセンブリ読み込みが増え、
メモリ使用量・起動時間が悪化する- 共通部分(マスタ ページ、ユーザー コントロール)を変更すると
結局多数の DLL が変わる- 差分配置は「何が本番に載っているか」を追いにくくする
現在の考え方(.NET Coreのデプロイ や
コンテナ)は逆に、「差分ではなく、丸ごと入れ替える」
(イミュータブルなデプロイ)方向に振れている。
差分配置は、配置に時間的・帯域的な制約がある場合の
妥協案と捉えるのが妥当である。
ASP.NET コンパイル ツールを使用して、厳密名付きのアセンブリを作成できる。
- 厳密名付きのアセンブリを使用するとアセンブリを不正なコードで置換することが困難になる。
- これによって、アプリケーションのセキュリティが向上する。
- 共有開発環境でのキー管理が複雑になる。
- FullTrust でないアセンブリから厳密名付きの Web サイトから厳密名付きのアセンブリを呼び出す場合、
呼び出し先の厳密名付きのアセンブリは AllowPartiallyTrustedCallersAttribute 属性を
持っている必要がある。
補足(厳密名の効果は限定的): アセンブリ でも述べた通り、
**厳密名は「発行元の証明」ではなく「ID の一意性」**である。「不正なコードで置換することが困難になる」のは、
同じ公開鍵トークンを持つアセンブリを作れないからであって、
署名鍵ごと差し替えられれば防げない
(web.configの参照を書き換えられる権限があるなら同じこと)。ファイルを置換されない、という保証が欲しいなら、
- ファイル システムの ACL(IIS ワーカーに書き込み権限を与えない)
- 読み取り専用のコンテナ イメージ
- 配置パイプラインの統制(手作業でのファイル配置を禁止する)
といった、運用側の対策の方が本質的である。
-
Visual Studio の Web サイトの[プロパティ ページ]ダイアログのリストから、
[MSBuild オプション]を選択し、以下のチェック ボックスを変更する。 -
各プリコンパイル オプションを組み合わせて利用することもでき、
「UI を更新可能な固定名・単一ページアセンブリ」というコンパイルも可能である。
= UI を更新できるプリコンパイル
= 固定名アセンブリへのプリコンパイル
= 署名されたアセンブリへのプリコンパイル
移行メモ(誤字): 原文の「利用することもで、」は
**「利用することもでき、」**の脱字と判断し修正した。
補足(この設定が使えるのは「Web サイト」プロジェクトのみ): 重要な前提として、
この[MSBuild オプション]は 「Web サイト」プロジェクトにのみ存在する。
「Web アプリケーション」プロジェクト(.csprojを持つ方)では、
そもそもコードは常にビルド時にコンパイルされるため、
本ページの悩みの大半は発生しない
(ASP.NETの構成(Webサイト・Webアプリ))。【Web サイト プロジェクト】 .csproj 無し。フォルダがそのままプロジェクト → コードも実行時コンパイル → 本ページの各オプションが要る 【Web アプリケーション プロジェクト】 .csproj あり → コードはビルド時コンパイル済み → 残るのは .aspx / .cshtml のみ(これも Web Deploy で事前コンパイル可)新規開発で「Web サイト」を選ぶ理由は現在ほぼ無く、
ASP.NET Core では区別自体が存在しない。
- ASP.NET コンパイル ツール (Aspnet_compiler.exe)
https://learn.microsoft.com/ja-jp/previous-versions/dotnet/netframework-4.0/ms229863(v=vs.100) - ASP.NET Core での Razor ファイルのコンパイル
https://learn.microsoft.com/ja-jp/aspnet/core/mvc/views/view-compilation
Tags: 移行, .NET開発, デプロイ