Skip to content

MS_Precompile

nishi_74322014 edited this page Sep 1, 2026 · 1 revision

プリコンパイル

概要

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 コンパイラによりコンパイルされる。
  • アプリケーション内のファイルに変更を加えると、次回ページが要求されたとき、
    変更されたファイルに対する依存関係を判断し、影響のあるファイルのみを、再び 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 コンパイル ツールを「-targetDir」スイッチを指定しないで実行することにより、
    開発フォルダ内で Web アプリケーションを JIT コンパイルする。

  • これを本番環境に配置した後、アプリケーション内のファイルを直接変更した場合、
    次回ページが要求されたとき、変更されたファイルに対する依存関係を判断し、
    影響のあるファイルのみを、再び JIT コンパイルする。

以下のケースで有用である。

  • 頻繁に変更される Web サイトを対象とする場合。
  • 初期応答速度を短くする必要がある場合。

メリット

  • 簡単に使用でき、応答速度に遅延が生じない。
  • 本番環境にソース コード ファイルを格納する必要がある。

デメリット

  • また、アプリケーション内のファイルを変更した場合は、
    JIT コンパイラによりコンパイルされるため、初期応答速度に遅延が生じる。

移行メモ(メリット欄の記載): 「本番環境にソース コード ファイルを
格納する必要がある」は、**メリットではなくデメリット(制約)**である
-targetDir を指定しないため、ソースが残ったまま配置される)。
原文の記載を保ちつつ、この点を注記しておく。

UI を更新できるプリコンパイル

  • ASP.NET コンパイル ツールの「-u」スイッチを使用することにより、
    ソース コードのみを DLL にコンパイルし、UI コード(「*.aspx」ファイルなど)は
    更新できるように残すことができる。
  • 本番環境に Web サイトを配置した後でも Web サイト全体を再コンパイルすることなく、
    UI コードを変更できる。

メリット

  • 簡単に使用でき、最初のページ要求時の応答時間を短くできる。
  • Web サイト全体を再コンパイルすることなく、Web サイトの外観や動作を変更できる。
  • プログラム コードという知的財産を保護できる。

デメリット

  • アプリケーションのすべての UI コード(*.aspx)を本番環境に格納する必要がある。

UI を更新できないプリコンパイル

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 ワーカーに書き込み権限を与えない)
  • 読み取り専用のコンテナ イメージ
  • 配置パイプラインの統制(手作業でのファイル配置を禁止する)

といった、運用側の対策の方が本質的である。

プリコンパイル オプションと[MSBuild オプション]の関連

  • 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 では区別自体が存在しない

参考

Microsoft Learn


Tags: 移行, .NET開発, デプロイ

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally