.NET TIPS

[ASP.NET]ページから生成されたソース・コードを見るには?

デジタルアドバンテージ
2003/06/27

 ASP.NETのパフォーマンスは、従来のASPに比べて大幅に改善されている。その理由の1つは、ASPがインタプリタ形式により実行されていたのに対して、ASP.NETではコンパイルされたWebページが実行されるためだ。

 .aspxファイルで記述されたASP.NETのページは、それが最初にアクセスされたときに、まずはC#やVisual Basic .NETのソース・コードに変換され、続けてコンパイラによりDLLファイル(アセンブリ)へとコンパイルされる。こうして作成されたアセンブリはメモリへロードされ、ページのインスタンスが作成されてから実行される。

 途中で作成されたソース・コードは、リリース・バージョンのWebアプリケーションであれば、コンパイル後は不要であるため削除されるが、アプリケーションがデバッグ用にコンパイルされた場合にはソース・コードはそのままとなる。このため.aspxファイルでの記述が実際にはどのようなコードに変換されているのかを確認することができる。

ソース・コードを生成するための準備

 Webアプリケーションをデバッグ用にコンパイルされるようにするには、.aspxファイルの先頭で記述する「@ Page」ディレクティブで、Debug属性をtrueにセットする。あるいは、Visual Studio .NETでWebアプリケーションを作成している場合などでは、web.configファイルで<compilation>要素のdebug属性をtrueにセットしてもよい。次の画面はVisual Studio .NETでweb.configファイルを開いたところだ。デフォルトではdebug属性はtrueとなっている。

web.configファイルの<compilation>要素
debug属性をtrueに設定すると、アプリケーションはデバッグ用にコンパイルされ、生成されるソース・コードを見ることができる。

 ここでは次のような単一ファイルからなる簡単なWebアプリケーションを実行して、実際に生成されるソース・コードを見てみよう。

<%@ Page Language="C#" Debug="true" %>
<html>
<head>
  <script runat="server">
    void onClick(Object s, CommandEventArgs e) {
      label.Text = "ボタンが押されました。";
    }
  </script>
</head>

<body>
  <form runat="server">

    <asp:Button runat="server" OnCommand="onClick" text="送信"  />
    <br>

    <asp:Label runat="server" font-size="30pt" id="label"  />

  </form>
</body>
</html>
単一ファイルからなる簡単なWebアプリケーション(simple.aspx)
この.aspxファイルから生成されるソース・コードを見るために、@ PageディレクティブのDebug属性をtrueに設定している。

 このアプリケーション(simple.aspx)は、[送信]ボタンがクリックされると、その下にメッセージを表示するだけだ。このファイルをIISのドキュメント・ルートである「\inetpub\wwwroot」にコピーして、ブラウザで「http://localhost/simple.aspx」をアクセスすれば実行できる。実行時の画面は次のようになる。

simple.aspxの実行画面
[送信]ボタンがクリックされたら、その下にメッセージを表示する。

ソース・コードが生成されるディレクトリ

 ソース・コードが生成される場所であるが、デフォルトでは、すべてのASP.NETのページが、次のディレクトリのさらに下に作成される(ちなみに、このディレクトリは上で触れたweb.configファイルの<compilation>要素のtempDirectory属性により変更可能)。

%SystemRoot%
  \Microsoft.NET
    \Framework
      \<バージョン番号>
        \Temporary ASP.NET Files

 ここで、%SystemRoot%はWindowsがインストールされているディレクトリである(C:\WindowsやC:\WinNTなど)。また、<バージョン番号>部分は、インストールされている.NET Frameworkのバージョンが入る。.NET Framework 1.0では「v1.0.3705」、.NET Framework 1.1では「v1.1.4322」となる。

 仮想ディレクトリを作成せずに、ドキュメント・ルート配下に.aspxファイルを配置した場合には、「Temporary ASP.NET Files」ディレクトリにある「root」ディレクトリのさらに下に2階層のディレクトリが作成され、そこにソース・コードが作成される(仮想ディレクトリを作成した場合には、「root」の代わりに仮想ディレクトリ名のディレクトリが作成される)。

 筆者の環境では、上記のアプリケーションは次のパスで示される.csファイルにソース・コードが生成された。

C:\WINDOWS
  \Microsoft.NET
    \Framework
      \v1.1.4322
        \Temporary ASP.NET Files
          \root
            \d16a94c5
              \8b912d73
                \mmnwd6wk.0.cs

 最後の2つのディレクトリ名やソース・コードのファイル名は、ほかのアプリケーションとかぶらないように、アプリケーション名とランダムな値をベースとしたハッシュ・アルゴリズムにより生成される。これらは実際にページにアクセスするまで分からないので、エクスプローラなどでファイルの更新日時を元に探すのが手っ取り早いだろう。

 あるいは「TIPS:実行ファイルのパスを取得するには?」で示した方法を用いて、次のようなコードを.aspxファイルの<body>要素中に記述すれば、正確なソース・コードのパスをブラウザ画面に表示することができる。

<%= System.Reflection.Assembly.GetExecutingAssembly().Location %>

 このコードにより表示されるパスは、実行されているアセンブリ(DLLファイル)のフルパスであるが、拡張子(.dll)を除いた部分を含んだ.csファイルが同じディレクトリ内に見つかるはずだ。また、ソース・コードのあるディレクトリ名だけならば、次のどちらかのコードでも表示させることができる(詳細な説明はここでは割愛する)。

<%= System.AppDomain.CurrentDomain.DynamicDirectory %>

<%= System.Web.HttpRuntime.CodegenDir %>

生成されたソース・コードの内容

 さて最後に、実際に生成されたソース・コードの中身を見ておこう。少し長いが上記のアプリケーションを実行したときに生成されたものを掲載しておく。なお、コメントやエラー時に行番号を表示するための#lineディレクティブ(VB.NETでは#ExternalSourceディレクティブ)は省略している。

namespace ASP {
  using System;
  using System.Collections;
  using System.Collections.Specialized;
  using System.Configuration;
  using System.Text;
  using System.Text.RegularExpressions;
  using System.Web;
  using System.Web.Caching;
  using System.Web.SessionState;
  using System.Web.Security;
  using System.Web.UI;
  using System.Web.UI.WebControls;
  using System.Web.UI.HtmlControls;

  [System.Runtime.CompilerServices.CompilerGlobalScopeAttribute()]
  public class simple_aspx : System.Web.UI.Page, System.Web.SessionState.IRequiresSessionState {

    private static int __autoHandlers;
    private System.Web.UI.WebControls.Button __control3;
    protected System.Web.UI.WebControls.Label label;
    private System.Web.UI.HtmlControls.HtmlForm __control2;
    private static bool __initialized = false;
    private static System.Collections.ArrayList __fileDependencies;

    void onClick(Object s, CommandEventArgs e) {
      label.Text = "ボタンが押されました。";
    }

    public simple_aspx() {
      System.Collections.ArrayList dependencies;
      if ((ASP.simple_aspx.__initialized == false)) {
        dependencies = new System.Collections.ArrayList();
        dependencies.Add("d:\\inetpub\\wwwroot\\simple.aspx");
        ASP.simple_aspx.__fileDependencies = dependencies;
        ASP.simple_aspx.__initialized = true;
      }
      this.Server.ScriptTimeout = 30000000;
    }

    protected override int AutoHandlers {
      get {
        return ASP.simple_aspx.__autoHandlers;
      }
      set {
        ASP.simple_aspx.__autoHandlers = value;
      }
    }

    protected System.Web.HttpApplication ApplicationInstance {
      get {
        return ((System.Web.HttpApplication)(this.Context.ApplicationInstance));
      }
    }

    public override string TemplateSourceDirectory {
      get {
        return "/";
      }
    }

    private System.Web.UI.Control __BuildControl__control3() {
      System.Web.UI.WebControls.Button __ctrl;
      __ctrl = new System.Web.UI.WebControls.Button();
      this.__control3 = __ctrl;
      __ctrl.Text = "送信";
      __ctrl.Command += new System.Web.UI.WebControls.CommandEventHandler(this.onClick);
      return __ctrl;
    }

    private System.Web.UI.Control __BuildControllabel() {
      System.Web.UI.WebControls.Label __ctrl;
      __ctrl = new System.Web.UI.WebControls.Label();
      this.label = __ctrl;
      __ctrl.Font.Size = System.Web.UI.WebControls.FontUnit.Parse("30pt", System.Globalization.CultureInfo.InvariantCulture);
      __ctrl.ID = "label";
      return __ctrl;
    }

    private System.Web.UI.Control __BuildControl__control2() {
      System.Web.UI.HtmlControls.HtmlForm __ctrl;
      __ctrl = new System.Web.UI.HtmlControls.HtmlForm();
      this.__control2 = __ctrl;
      System.Web.UI.IParserAccessor __parser = ((System.Web.UI.IParserAccessor)(__ctrl));
      __parser.AddParsedSubObject(new System.Web.UI.LiteralControl("\r\n\r\n\t\t"));
      this.__BuildControl__control3();
      __parser.AddParsedSubObject(this.__control3);
      __parser.AddParsedSubObject(new System.Web.UI.LiteralControl("\r\n\t\t<br>\r\n\r\n\t\t"));
      this.__BuildControllabel();
      __parser.AddParsedSubObject(this.label);
      __parser.AddParsedSubObject(new System.Web.UI.LiteralControl("\r\n\r\n\t"));
      return __ctrl;
    }

    private void __BuildControlTree(System.Web.UI.Control __ctrl) {
      System.Web.UI.IParserAccessor __parser = ((System.Web.UI.IParserAccessor)(__ctrl));
      __parser.AddParsedSubObject(new System.Web.UI.LiteralControl("\r\n<html>\r\n<head>\r\n\t"));
      __parser.AddParsedSubObject(new System.Web.UI.LiteralControl("\r\n</head>\r\n\r\n<body>\r\n\t"));
      this.__BuildControl__control2();
      __parser.AddParsedSubObject(this.__control2);
      __parser.AddParsedSubObject(new System.Web.UI.LiteralControl("\r\n</body>\r\n</html>\r\n"));
    }

    protected override void FrameworkInitialize() {
      this.__BuildControlTree(this);
      this.FileDependencies = ASP.simple_aspx.__fileDependencies;
      this.EnableViewStateMac = true;
      this.Request.ValidateInput();
    }

    public override int GetTypeHashCode() {
      return 583770433;
    }
  }
}
simple.aspxをアクセスしたときに生成されるソース・コード

 生成されたソース・コードには、1つのクラス「simple_aspx」が含まれているのが分かる。このクラスのインスタンスが、ブラウザでsimple.aspxをアクセスしたときに実際に実行されるものだ。クラス名は基本的に、.aspxファイルのファイル名のピリオドをアンダースコア(“_”)で置き換えたものになる(クラス名は@ PageディレクティブのClassName属性で指定可能)。

 またこのsimple_aspxクラスは、Pageクラス(System.Web.UI名前空間)を継承しているのを確認することができる。アプリケーション内でIsPostBackプロパティなどのPageクラスのプロパティを利用できるのはこのためだ。Visual Studio .NETなどで、コードビハインドにより.aspxファイルと.csファイル(あるいは.vbファイル)を分離して記述している場合には、.csファイル内で記述されたクラスがPageクラスを継承し、生成されるソース・コードではそのクラスをさらに継承したクラスとなる。

 リストの最後の方にあるFrameworkInitializeメソッドは、このクラスがインスタンス化されたときに最初にシステムにより呼び出されるメソッドである。このメソッドではさらに__BuildControlTreeメソッドを呼び出し、ページ内の各コントロールのオブジェクトを作成する。注意深くソース・コードを読んでいけば、そのメソッド名が表しているように各コントロールのインスタンスはツリー状に構成されているのが分かるだろう。コントロールのツリーの様子は、ページのトレース情報を表示させても確認することができる。トレース情報の表示については「TIPS:[ASP.NET]ページのトレース情報を出力するには?」を参照していただきたい。End of Article

カテゴリ:Webフォーム 処理対象:ページ
使用ライブラリ:Pageクラス(System.Web.UI名前空間)
使用キーワード:@Pageディレクティブ
使用キーワード:<compilation>要素
関連TIPS:実行ファイルのパスを取得するには?
関連TIPS:
[ASP.NET]ページのトレース情報を出力するには?
 
この記事と関連性の高い別の.NET TIPS
プログラムからソース・コードをコンパイルするには?
ファイルやディレクトリの一覧を取得するには?
[ASP.NET]ポストとポストバックの違いは?
C#のソース・コードを実行するには?
ファイルやディレクトリの作成/変更/削除を監視するには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間