ASP.NET ページのコードビハインドクラスはなぜ partial でなければならないのか?

ASP.NET のコードビハインドで定義するクラスは partial を指定しなければなりません。

ASP.NET のページの型を調べたときに使ったテストファイルから、partial 指定を削除して、 エラーが出る様子を確認しましょう。

partial を指定しないとコンパイルエラーが発生する

エラーメッセージをよく読むと、確かに partial を指定していないことがエラーの原因になっています。

ここをもう少し掘り下げてみましょう。

エラーページのエラーメッセージを見ると次のようになっています。(パス名は一部 ... として短縮しています)

> "C:\Windows\Microsoft.NET\...\v2.0.50727\csc.exe" /t:library /utf8output 
/R:"C:\Windows\assembly\GAC_32\System.Web\...\System.Web.dll" 
/R:"C:\Windows\assembly\GAC_32\System.En...\System.EnterpriseServices.dll" 
/R:"C:\Windows\assembly\GAC_MSIL\System.We...\System.Web.Services.dll" 
/R:"C:\Windows\assembly\GAC_32\System.Data...\System.Data.dll" 
/R:"C:\Windows\assembly\GAC_MSIL\Syste...\System.Runtime.Serialization.dll" 
/R:"C:\Windows\assembly\GAC_MSIL\System.We...\System.Web.Mobile.dll" 
/R:"C:\Windows\assembly\GAC_MSIL\System.Co...\System.Configuration.dll" 
/R:"C:\Windows\assembly\GAC_MSIL\System.Dr...\System.Drawing.dll" 
/R:"C:\Windows\Microsoft.NET\Framework\v2....\mscorlib.dll" 
/R:"C:\Windows\assembly\GAC_MSIL\System.Wo...\System.WorkflowServices.dll" 
/R:"C:\Windows\assembly\GAC_MSIL\System.Id...\System.IdentityModel.dll" 
/R:"C:\Windows\assembly\GAC_MSIL\System\2....\System.dll" 
/R:"C:\Windows\assembly\GAC_MSIL\System.Xm...\System.Xml.dll" 
/R:"C:\Windows\assembly\GAC_MSIL\System.Se...\System.ServiceModel.Web.dll" 
/R:"C:\Windows\assembly\GAC_MSIL\System.Se...\System.ServiceModel.dll" 
/out:"C:\...\Framework\v2.0.50727\Temp... Files\...\App_Web_hik9z6ee.dll" 
/D:DEBUG /debug+ /optimize- /w:4 /nowarn:1659;1699;1701  
"C:\...\Framework\v2.0.50727\Temp...NET Files\a...\App_Web_hik9z6ee.0.cs" 
"C:\...\Framework\v2.0.50727\Temp...NET Files\a...\App_Web_hik9z6ee.1.cs" 
"C:\...\Framework\v2.0.50727\Temp...NET Files\a...\App_Web_hik9z6ee.2.cs" 
"C:\...\Framework\v2.0.50727\Temp...NET Files\a...\App_Web_hik9z6ee.3.cs" 
"C:\...\Framework\v2.0.50727\Temp...NET Files\a...\App_Web_hik9z6ee.4.cs" 
"C:\...\Framework\v2.0.50727\Temp...NET Files\a...\App_Web_hik9z6ee.5.cs" 
"C:\...\Framework\v2.0.50727\Temp...NET Files\a...\App_Web_hik9z6ee.6.cs" 
"C:\...\Framework\v2.0.50727\Temp...NET Files\a...\App_Web_hik9z6ee.7.cs"


Microsoft (R) Visual C# 2005 Compiler version 8.00.50727.4927
for Microsoft (R) Windows (R) 2005 Framework version 2.0.50727
Copyright (C) Microsoft Corporation 2001-2005. All rights reserved.

C:\test\getTypes2.aspx.cs(4,15): error CS0260: 
Missing partial modifier on declaration of type 'MyTest.getTypes2'; 
another partial declaration of this type exists
c:\Windows\Microsoft.NET\Framework\v2.0.50727\Temporary 
ASP.NET Files\aspnetstepbystep\ce26f8e4
\5bcf135b\App_Web_hik9z6ee.2.cs(15,26): 
(Location of symbol related to previous error)

.NET Framework システムフォルダ内の csc (C# コンパイラ) が実行されています。 このときに、/R オプションで GAC 内のアセンブリが多数参照されており、 さらに、*.cs ソースコードが実に 8 つもまとめてコンパイルされています。

要らないような参照も多々ありますが、ソースコードの中身を判別して必要な参照を選定するより、 まとめて参照してしまったほうが実行速度が速いんでしょうね。

さて、ソースコードは ASP.NET が自動生成しているファイルです。

このうち App_Web_hik9z6ee.3.cs は次のような内容です (一部省略)。

#pragma checksum "C:\test\getTypes2.aspx.cs" ...

#line 1 "C:\test\getTypes2.aspx.cs"
using System;

namespace MyTest {
   public class getTypes2 : System.Web.UI.Page {

      public void ShowType() {
         Type t;
         t = this.GetType();
         
         while ( true ) {
            Response.Write( t.ToString() + "<br>" );
            if ( t == typeof( System.Object ) ) {
               break;
            }
            t = t.BaseType;
         };
      }
   }
}

#line default
#line hidden

これは丸ごと、getType2.aspx.cs の内容ですね。ASP.NET がコンパイルするときにファイルの内容をコピーしているんですね。

さらに App_Web_hik9z6ee.3.cs を見ると次の内容です。よく見ると確かにこの中に getTypes2 クラスが partial で指定されています。 こちらは ASPX ファイルを元に生成されたファイルです。

#pragma checksum "C:\test\getTypes2.aspx" ...
//-------------------------------------------------------------------------
// 
//     This code was generated by a tool.
//     Runtime Version:2.0.50727.4927
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// 
//-------------------------------------------------------------------------

namespace MyTest {          public partial class getTypes2 : System.Web.SessionState.IRequiresSessionState {           protected System.Web.Profile.DefaultProfile Profile {        get {          return ((System.Web.Profile.DefaultProfile)(this.Context.Profile));        }      }           protected System.Web.HttpApplication ApplicationInstance {        get {          return ((System.Web.HttpApplication)( this.Context.ApplicationInstance));        }      }    } }
namespace ASP {       #line 285 "C:\Windows\Micro...ramework\v2.0.50727\Config\web.config"    using System.Web.Profile;       #line default    #line hidden       #line 280 "C:\Windows\Micro...ramework\v2.0.50727\Config\web.config"    using System.Text.RegularExpressions;       #line default    #line hidden       #line 282 "C:\Windows\Micro...ramework\v2.0.50727\Config\web.config"    using System.Web.Caching;       #line default    #line hidden       #line 278 "C:\Windows\Micro...ramework\v2.0.50727\Config\web.config"    using System.Configuration;       #line default    #line hidden       #line 277 "C:\Windows\Micro...ramework\v2.0.50727\Config\web.config"    using System.Collections.Specialized;       #line default    #line hidden       #line 289 "C:\Windows\Micro...ramework\v2.0.50727\Config\web.config"    using System.Web.UI.HtmlControls;       #line default    #line hidden       #line 287 "C:\Windows\Micro...ramework\v2.0.50727\Config\web.config"    using System.Web.UI.WebControls;       #line default    #line hidden       #line 276 "C:\Windows\Micro...ramework\v2.0.50727\Config\web.config"    using System.Collections;       #line default    #line hidden       #line 286 "C:\Windows\Micro...ramework\v2.0.50727\Config\web.config"    using System.Web.UI;       #line default    #line hidden       #line 288 "C:\Windows\Micro...ramework\v2.0.50727\Config\web.config"    using System.Web.UI.WebControls.WebParts;       #line default    #line hidden       #line 275 "C:\Windows\Micro...ramework\v2.0.50727\Config\web.config"    using System;       #line default    #line hidden       #line 284 "C:\Windows\Micro...ramework\v2.0.50727\Config\web.config"    using System.Web.Security;       #line default    #line hidden       #line 281 "C:\Windows\Micro...ramework\v2.0.50727\Config\web.config"    using System.Web;       #line default    #line hidden       #line 283 "C:\Windows\Micro...ramework\v2.0.50727\Config\web.config"    using System.Web.SessionState;       #line default    #line hidden       #line 279 "C:\Windows\Micro...ramework\v2.0.50727\Config\web.config"    using System.Text;       #line default    #line hidden          [System.Runtime.CompilerServices.CompilerGlobalScopeAttribute()]    public class gettypes2_aspx : global::MyTest.getTypes2, System.Web.IHttpHandler {           private static bool @__initialized;           private static object @__fileDependencies;           [System.Diagnostics.DebuggerNonUserCodeAttribute()]      public gettypes2_aspx() {        string[] dependencies;               #line 912304 "C:\test\getTypes2.aspx.cs"        ((global::System.Web.UI.Page)(this)).AppRelativeVirtualPath = "~/getTypes2.aspx";               #line default        #line hidden        if ((global::ASP.gettypes2_aspx.@__initialized == false)) {          dependencies = new string[2];          dependencies[0] = "~/getTypes2.aspx";          dependencies[1] = "~/getTypes2.aspx.cs";          global::ASP.gettypes2_aspx.@__fileDependencies = this.GetWrappedFileDependencies(dependencies);          global::ASP.gettypes2_aspx.@__initialized = true;        }        this.Server.ScriptTimeout = 30000000;      }           [System.Diagnostics.DebuggerNonUserCodeAttribute()]      private void @__BuildControlTree(gettypes2_aspx @__ctrl) {               #line 1 "C:\test\getTypes2.aspx"        this.InitializeCulture();               #line default        #line hidden        @__ctrl.SetRenderMethodDelegate( new System.Web.UI.RenderMethod(this.@__Render__control1));      }           private void @__Render__control1(System.Web.UI.HtmlTextWriter @__w, System.Web.UI.Control parameterContainer) {        @__w.Write("\r\n\r\n\r\n

font-size:large;\">\r\n ");               #line 9 "C:\test\getTypes2.aspx"       ShowType();               #line default        #line hidden        @__w.Write("\r\n

\r\n\r\n\r\n"
);      }                #line 912304 "C:\test\getTypes2.aspx.cs"      [System.Diagnostics.DebuggerNonUserCodeAttribute()]      protected override void FrameworkInitialize() {        base.FrameworkInitialize();        this.@__BuildControlTree(this);        this.AddWrappedFileDependencies( global::ASP.gettypes2_aspx.@__fileDependencies);        this.Request.ValidateInput();      }           #line default      #line hidden           [System.Diagnostics.DebuggerNonUserCodeAttribute()]      public override int GetTypeHashCode() {        return 909526700;      }           [System.Diagnostics.DebuggerNonUserCodeAttribute()]      public override void ProcessRequest(System.Web.HttpContext context) {        base.ProcessRequest(context);      }    } }

前半の赤で囲んだ箇所にて、コードビハインドで定義したクラスに付け足したいクラス定義が partial で定義されています。

中身を良く見ると、IRequiresSessionState というインターフェイスが付け足され、さらに Profile と ApplicationInstance というプロパティが追加されています。

namespace MyTest {
   
   
   public partial class getTypes2 : 
System.Web.SessionState.IRequiresSessionState {
     
     protected System.Web.Profile.DefaultProfile Profile {
       get {
         return ((System.Web.Profile.DefaultProfile)(this.Context.Profile));
       }
     }
     
     protected System.Web.HttpApplication ApplicationInstance {
       get {
         return ((System.Web.HttpApplication)(
this.Context.ApplicationInstance));
       }
     }
   }
}

後半の ASP.gettypes2_aspx クラスについては、gettype2.aspx を ASP.NET のランタイムが処理した結果生成されたクラスですが、 こちらは逆に partial クラス指定ではありません。

@__Render__control1 メソッドで、ASPX ファイルに記述されたテキストが HtmlTextWriter を用いて出力されていることがわかります。

連続した空白文字などもご丁寧にそのまま出力していることがよくわかります。ブラウザで無視される文字はこの時点で取り去る最適化オプションがあってもよさそうですけど・・・。

IRequiresSessionState マーカーインターフェイス

さて、IRequiresSessionState というインターフェイスに着目してみます。その名前からこれは SessionState と関連していそうです。 その点を以下のページで少し掘り下げて見ましょう。

» EnableSessionState ディレクティブは無視できる?!

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 ASP.NET 入門