65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET 1.1 Web 应用程序编译和预编译

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.42/5 (9投票s)

2005 年 8 月 11 日

CPOL

18分钟阅读

viewsIcon

91302

downloadIcon

1090

介绍如何预编译或编译 C# 或 VB ASP.NET 1.1 Web 应用程序的 .aspx 和 .ascx 文件;包含完整的源代码、编译库、运行时库和一个演示项目。

请使用文章 ASP.NET 1.1 Web 应用程序编译和预编译 - 增强版 中提供的新版本源代码。

引言

如果您曾想过预编译(即让 ASP.NET 运行时在单个 HTTP 请求中编译所有页面和用户控件)一个基于 ASP.NET 1.1 的 Web 应用程序,或者将所有 .ASPX 页面和 .ASCX 用户控件编译成一个程序集 - 这里有一个解决方案可以实现:

  • 预编译应用程序中的所有 .ASPX.ASCX 页面和用户控件,而无需实际向它们发出 HTTP 请求(即,页面将被编译但不会执行)。
  • 为所有 .ASPX.ASCX 文件生成源代码,并将它们编译成程序集;它还允许您将任何外部文件(样式表、JavaScript 文件、图像等)嵌入到程序集中作为 Win32 资源。

如果选择编译,则需要部署

  • Global.asax
  • Web.config
  • 程序集到 bin 目录。
  • 外部文件(.css.js.gif 等),如果未嵌入。

如果应用程序使用多个 web.config 文件,则需要将它们部署到相应的目录。为了让 IIS 将对目录(例如 https://)发出的请求重定向到默认文档(https:///Default.aspx),您需要在需要重定向的每个目录中部署空的 Default.aspx 文件。原因是当请求一个目录时,IIS 会在该目录中搜索默认文档(Index.htmlDefault.aspx 等),如果找不到,则返回错误或目录内容。如果您在目录中放置了 Default.aspx,IIS 将把请求转发给 ASP.NET 运行时。

您无需部署任何额外的 .aspx.ascx 文件,除非有未编译的文件 - 即,您可以组合编译和未编译的页面。如果页面或用户控件已编译,则运行它不需要 .aspx.ascx 文件。如果您选择不编译某些页面和/或用户控件,则需要部署它们。

对所有嵌入式外部文件的请求会像对普通文件的请求一样被处理。为了让 IIS 将此类请求转发给 ASP.NET 运行时,您需要将这些文件名扩展名映射到 aspnet_isapi.dll

Application

该解决方案已在 **C#** 和 **VB** ASP.NET 1.1 项目上进行了测试。它可能也适用于其他编程语言,因为它不利用依赖于语言的特性。

**VB 开发人员注意事项:** VB 项目存在一个问题,因为 VB 编译器不会像 C# 编译器那样移除未使用的程序集引用。也就是说,如果将程序集引用传递给编译器,而该程序集实际上未被代码使用,编译器仍会在编译的程序集中添加该引用。因此,在编译应用程序(.aspx.ascx 文件)时,ASP.NET 运行时自动生成的程序集引用可能会添加到程序集中。为防止这种情况,在生成源代码期间会移除此类引用,但这可能也会移除一些有效的引用,从而阻止编译。为避免此问题,您的项目不应使用名称为八个字符、仅包含小写字母和/或数字的程序集。有关更多信息,请参阅 WebApp.Web.Compilation.Compilation.IsAutoGeneratedAssembly 方法。

预编译如何工作

为了让 ASP.NET 运行时在不发出 HTTP 请求的情况下编译页面,需要调用 System.Web 程序集中的公共静态方法 System.Web.UI.PageParser.GetCompiledPageInstance(String, String, HttpContext)。参数是到页面的虚拟路径、到页面的物理路径和 HttpContext。例如,您可以使用以下代码预编译一个页面

System.Web.UI.PageParser.GetCompiledPageInstance("~/MyPage.aspx", 
                               MapPath( "~/MyPage.aspx" ), context)

此方法首先检查页面是否已编译且 .aspx 文件内容未更改,如果未更改,则解析页面并编译生成的代码。在解析阶段,如果页面直接使用任何用户控件,它们也会被解析和编译。

仅当存在不直接在页面中使用而是通过 System.Web.UI.TemplateControl.LoadControl(String)System.Web.UI.TemplateControl.LoadTemplate(String) 方法加载的用户控件时,才需要预编译用户控件。否则,所有用户控件应在页面预编译期间由 ASP.NET 运行时进行编译。要让 ASP.NET 运行时编译用户控件,应调用 System.Web.UI.UserControlParser.GetCompiledUserControlType(String, String, HttpContext) 方法。参数与 GetCompiledPageInstance 相同,但该方法是内部静态的,System.Web.UI.UserControlParser 类型也是如此,因此应通过反射调用它。

如何预编译应用程序

源代码包含一个名为“Compilation.aspx”的页面。它是一个独立的页面,不需要编译其代码隐藏即可运行(在 @Page 指令中应用了“src”属性)。要预编译应用程序:

  1. 编译应用程序的代码隐藏(如果需要)。
  2. WebApp.Web.CompilationWebApp.Web.Compilation.Runtime 程序集(随源代码提供)放在应用程序的 bin 目录中。
  3. 将“Compilation.aspx”和“Compilation.aspx.cs”放在应用程序的根目录中。
  4. 使用“Compilation.aspx”预编译所有 .aspx.ascx 文件。

将 .aspx 和 .ascx 文件编译到程序集

该解决方案允许您为应用程序中所有或部分 .aspx.ascx 文件生成源代码,并将它们编译成程序集。它还允许您将应用程序所需的任何外部文件(.css.js.gif 等)嵌入到同一程序集或另一个程序集中,并以与它们是外部文件时相同的方式使用这些文件。

该解决方案由两个 C# 项目组成:

  • WebApp.Web.Compilation - 包含允许您预编译、编译和嵌入资源的类型;需要 WebApp.Web.Compilation.Runtime
  • WebApp.Web.Compilation.Runtime - 包含运行编译应用程序(HTTP 处理程序、资源管理器)所需的类型。

编译过程包括以下步骤:

  1. 代码隐藏编译
  2. 为所有或部分 .aspx.ascx 文件生成代码。
  3. 添加外部资源(如果您愿意)。
  4. 将生成的代码和资源编译到程序集。

代码隐藏编译

必须编译项目的代码隐藏,以便 .aspx.ascx 文件能够被解析。如果页面中应用了 src 属性,则它们应排除在编译过程之外。

如果您为某些页面或用户控件使用 src 属性,则它们的 .aspx.ascx 文件无法编译,因为您无法编译生成的源代码 - 这要求基类型的源代码(代码隐藏)也参与编译或已在程序集中编译。

为所有或部分 .aspx 和 .ascx 文件生成代码

此步骤以及后续步骤可以通过使用 Compilation.aspx 来完成,或者通过开发利用 WebApp.Web.Compilation 程序集的自定义代码来完成。Compilation.aspx 允许您指定程序集名称、保存生成的源代码的位置以及要嵌入的资源文件。但是,Compilation.aspx 会为应用程序根目录及其子目录中的所有 .aspx.ascx 文件生成代码,因此如果有人希望自定义过程,则需要修改页面或编写自己的代码。

如果您只想编译应用程序 - 您可以使用 Compilation.aspx 并直接跳转到“编译后的应用程序在运行时”部分。只需按照“如何预编译应用程序”中的步骤进行操作。唯一的建议是先预编译您的应用程序,以便您能够意识到任何解析错误并在编译前修复它们。Compilation.aspx 显示预编译或编译期间发现的所有错误的详细输出。

对于其他需要更多详细信息或定制化编译的用户:

编译过程的核心是 WebApp.Web.Compilation.Compilation.GenerateCode(HttpContext,string) 方法。它允许您为不包含解析错误的任何 .aspx.ascx.asax 文件生成代码。生成 Global.asax 的代码是可能的,但可能不可用,因为没有普通的方法来处理此类请求。

WebApp.Web.Compilation.GenerateCode 只能在活动的 HTTP 上下文中执行 - 即在发出对应用程序的请求时。这是因为该方法利用 ASP.NET 运行时来解析文件并通过反射获取生成的代码。

该方法会创建 .NET Framework 提供的解析器之一的实例:System.Web.UI.PageParserSystem.Web.UI.UserControlParserSystem.Web.UI.ApplicationFileParser 以及它们各自的编译类(它们通过使用提供的解析器实例实际生成代码):System.Web.Compilation.PageCompilerSystem.Web.Compilation.UserControlCompilerSystem.Web.Compilation.ApplicationFileCompiler。所有类型都是内部的(除了 System.Web.UI.PageParser),并且它们都有内部构造函数,因此实例是通过反射创建的。为了绕过这些类型的标准初始化和使用,反射被用来直接获取或设置内部/私有属性和字段的值。结果是获得了生成的代码,但页面或用户控件并未真正编译 - 即没有生成程序集(就像当控件被 ASP.NET 运行时正常解析时一样)。这排除了页面或用户控件使用其他用户控件的场景。在这种情况下,这些其他控件会在控件的解析过程中被编译,但这并不重要。

在获得生成的代码(System.CodeDom.CodeCompileUnit 实例)后,需要处理以下问题:

  • 重命名生成的类型

    这是必需的,因为 ASP.NET 运行时会从解析的文件名派生类型名 - 即,如果您在不同目录中有两个同名的文件,它们生成的类型将具有相同的名称。因此,您不能在 .aspx 页面中使用两个同名的不同用户控件 - 当 ASP.NET 运行时尝试编译页面时会发生编译错误。类型的新名称是从页面或用户控件的相对物理路径(基于应用程序的根目录)派生出来的。可以通过修改 WebApp.Web.Compilation.Runtime.CompilationUtils.GetTypeName 方法来自定义此行为,该方法根据指定的物理路径生成命名空间和类型名称。WebApp.Web.Compilation.Runtime.CompilationUtils.GetTypeName 也用于在运行时(当发出对页面或用户控件的请求时)获取与指定虚拟路径对应的类型名称。

  • 重命名生成类型的名称的所有用法

    这是通过枚举生成类型中的方法和表达式并进行修复来完成的。可以在生成源代码后通过检查来确定查找这些用法的模式。

  • 修复所有使用的用户控件的类型名称

    这是必需的,原因如下:

    • 用户控件实例不是通过使用 System.Web.UI.TemplateControl.LoadControl(String) 方法获得的。而是直接创建和初始化实例。
      private ASP.WebUserControl1_ascx __control3;
      
      // ...
      
      private System.Web.UI.Control __BuildControl__control3()
      {
          ASP.WebUserControl1_ascx __ctrl;
          
          #line 19 "..."
          __ctrl = new ASP.WebUserControl1_ascx();
      
          // ...
      }
      
      public void __DataBindcontrol__control3(object sender, 
                                           System.EventArgs e)
      {
          System.Web.UI.Control Container;
          ASP.WebUserControl1_ascx target;
          
          #line 96 "..."
          target = ((ASP.WebUserControl1_ascx)(sender));
      
          // ...
      }
    • 对于页面或用户控件直接使用的所有用户控件,都需要生成源代码。否则,页面或用户控件的源代码无法编译(因为它所需的一些类型将不存在)。因此,如果页面或用户控件直接使用另一个用户控件,它们也应该被编译。

    在此步骤中,会修复用户控件类型的所有用法。类型的名称是在不考虑源文件的情况下确定的 - 通过访问解析器实例的属性(FileDependencies)来获得包含文件路径的集合。

  • 创建 Win32 资源文件 (.res)

    对于大多数页面和用户控件,ASP.NET 运行时会生成一个 Win32 资源文件,其中包含页面或用户控件的 HTML 内容的部分。运行时将该文件传递给编译器,其内容将嵌入到生成的程序集中。然后在页面/用户控件的渲染阶段在运行时使用此内容。我们将在编译步骤中使用此文件。

上述所有步骤都实现在 WebApp.Web.Compilation.Compilation.GenerateCode(HttpContext,string) 方法中。

WebApp.Web.Compilation.Compilation 类提供 BatchGenerateCode,允许您为指定目录及其子目录中指定类型(.aspx.ascx.asax)的所有文件生成代码。

添加外部资源

在添加任何外部文件之前,必须调用 WebApp.Web.Compilation.Compilation.CreateCompilerParameters。此方法将所有 System.CodeDom.CodeCompileUnit 实例的程序集引用和所有资源文件合并到一个资源文件中。如果希望将所有生成的代码编译到单个程序集中,则需要这样做。否则,每个 System.CodeDom.CodeCompileUnit 都可以编译到包含其自身 Win32 资源文件数据的独立程序集中。WebApp.Web.Compilation.Compilation.CreateCompilerParameters 还更改了 System.CodeDom.CodeCompileUnit 实例中资源加载的方式。这是必需的,因为资源的名称已更改,以便将它们合并到公共资源文件中。

在构建了公共资源文件后,可以使用 WebApp.Web.Compilation.Compilation.AddFileToResourcesWebApp.Web.Compilation.Compilation.AddFilesToResources 方法将其他文件作为资源添加到其中。此方法允许您指定正在添加的资源的自定义名称和类型。默认值在 WebApp.Web.Compilation.Runtime.ResourceManager 中定义。

对于所有您希望在运行时显示为外部文件的资源,都需要构建一个索引 - 这是由 WebApp.Web.Compilation.Compilation.AddIndexToResources 方法完成的。此方法添加一个索引,其中包含文件的相对应用程序根目录名称以及它们的 Win32 资源条目的名称和类型。

您还可以通过 WebApp.Web.Compilation.Compilation.CompileResoucesToAssembly 方法构建自己的资源文件(WebApp.Web.Compilation.Compilation.AddFileToResourcesWebApp.Web.Compilation.Compilation.AddFilesToResources 将资源文件的路径作为参数)并将其编译到单独的程序集中。在运行时,可以通过利用 WebApp.Web.Compilation.Runtime.ResourceManager 类型中的方法来访问资源。

将生成的代码和资源编译到程序集

编译由 WebApp.Web.Compilation.Compilation.CompileToAssembly 方法完成。如果将 outputPath 参数设置为非 null 值,则还将生成源代码并将其保存在指定目录中。否则,将直接编译 System.CodeDom.CodeCompileUnit 实例(实际上,源代码文件由 .NET Framework 在临时目录中创建)。

您还可以使用 WebApp.Web.Compilation.Compilation.GenerateSourceCode 方法生成源代码文件而不将其编译到程序集中。

编译后的应用程序在运行时

在运行时,应处理以下事项:

  • 处理对编译页面的请求。
  • 加载编译用户控件的能力。
  • 处理对嵌入资源的请求。

以上所有内容均在 WebApp.Web.Compilation.Runtime 程序集中实现,并且运行应用程序不需要 WebApp.Web.Compilation

处理对编译页面的请求

这是由 WebApp.Web.Compilation.Runtime.CompiledPageHandlerFactory 类型完成的。它实现了 System.Web.IHttpHandlerFactory,其 GetHandler 方法返回 System.Web.IHttpHandler 实例,在 .aspx 页面的情况下,该实例的类型为 System.Web.UI.Page

要启用处理程序,应在 web.config 中包含以下内容:

<system.web>
  <httphandlers>
    <add verb="*" path="*.aspx" 
      type="WebApp.Web.Compilation.Runtime.CompiledPageHandlerFactory,
                                  WebApp.Web.Compilation.Runtime" />
  </httpHandlers>
</system.web>

这将导致 ASP.NET 运行时通过 WebApp.Web.Compilation.Runtime.CompiledPageHandlerFactory.GetHandler 方法获取对所有 .aspx 文件请求的处理程序。该方法本身会调用 WebApp.Web.Compilation.Runtime.CompiledControlManager.LoadPage 来获取 System.Web.UI.Page 实例。

WebApp.Web.Compilation.Runtime.CompiledControlManager.LoadPage 的行为如下:

如果 WebApp.Web.Compilation.Runtime.CompiledControlManager 已初始化,它会尝试创建页面已编译类型的实例。如果页面未编译(即,不存在对应的类型),并且允许处理未编译的页面(可以通过配置禁止),它会以内置的 .aspx 处理程序(System.Web.UI.PageHandlerFactory)相同的方式获取页面实例 - 通过调用 System.Web.UI.PageParser.GetCompiledPageInstance(String, String, HttpContext) 方法。这允许组合编译和未编译的页面。

如果 WebApp.Web.Compilation.Runtime.CompiledControlManager 未初始化,则无论是否允许处理未编译的页面,都会调用 System.Web.UI.PageParser.GetCompiledPageInstance(String, String, HttpContext)

因此,WebApp.Web.Compilation.Runtime.CompiledControlManager.LoadPage 将:

  • 尝试查找与请求的页面对应的类型并创建其实例。
  • 如果找不到对应的类型并且允许处理未编译的页面,则页面将以标准 .aspx 处理程序的方式加载。

这意味着,如果您选择不编译某些页面,对它们的请求将正常处理,并且任何人也不能通过在目录中放置 .aspx 文件来替换页面,因为该方法首先检查已编译的类型。此外,您可以禁止处理未编译的页面。

要配置 WebApp.Web.Compilation.Runtime.CompiledControlManager,需要在 web.config 中包含以下内容:

<configSections>
    <section name=
        "WebApp.Web.Compilation.Runtime.CompiledControlManager" 
        type="System.Configuration.NameValueSectionHandler,
        System, Version=1.0.5000.0, Culture=neutral, 
        PublicKeyToken=b77a5c561934e089"
        allowLocation="false" />
</configSections>
<WebApp.Web.Compilation.Runtime.CompiledControlManager>
    <add key="CompiledPageAssembly" value="UI" />
    <add key="CompiledUserControlAssembly" value="UI" />
    <add key="AllowNonCompiledPages" value="false" />
    <add key="AllowNonCompiledUserControls" value="false" />
</WebApp.Web.Compilation.Runtime.CompiledControlManager>

这会同时配置页面和用户控件。您可以指定不同的程序集(如果适用),并且可以选择跳过用户控件的配置,例如,如果只有页面已编译。程序集是通过调用 System.Reflection.Assembly.Load 方法加载的。

或者,您可以使用这些方法:

[编辑说明:使用单个空格以避免滚动。]

  • WebApp.Web.Compilation.Runtime.CompiledControlManager. InitCompiledControls
  • WebApp.Web.Compilation.Runtime.CompiledControlManager. InitCompiledPages
  • WebApp.Web.Compilation.Runtime.CompiledControlManager. InitCompiledUserControls

加载编译用户控件的能力

要加载编译的用户控件,需要分别使用 WebApp.Web.Compilation.Runtime.CompiledControlManager.LoadControlWebApp.Web.Compilation.Runtime.CompiledControlManager.LoadTemplate 方法,而不是 System.Web.UI.TemplateControl.LoadControl(String)System.Web.UI.TemplateControl.LoadTemplate(String) 方法。这些方法与 WebApp.Web.Compilation.Runtime.CompiledControlManager.LoadPage 方法的行为相同,即它们尝试查找与请求的控件对应的类型,如果失败并且允许处理未编译的用户控件,则会回退到 System.Web.UI.TemplateControl.LoadControl(String)System.Web.UI.TemplateControl.LoadTemplate(String) 方法。

请注意,System.Web.UI.PageSystem.Web.UI.TemplateControl 的子类,因此您只需将以下方法放在派生自 System.Web.UI.Page 的类中,并将该类作为页面的基类即可。

public new Control LoadControl( string virtualPath )
{
  return WebApp.Web.Compilation.Runtime.CompiledControlManager.LoadControl(
                                                     this, virtualPath );
}

public new ITemplate LoadTemplate( string virtualPath )
{
  return WebApp.Web.Compilation.Runtime.CompiledControlManager.LoadTemplate(
                                                          this, virtualPath );
}

处理对嵌入资源的请求

要启用对嵌入资源的请求处理,就像它们是外部文件一样,您需要执行以下操作:

  • 在 IIS 管理控制台中为应用程序将所需的文件扩展名映射到“aspnet_isapi.dll”,以便将此类文件中的请求转发给 ASP.NET 运行时。请注意,您应该取消选中“检查文件是否存在”复选框,这样 IIS 将不会验证文件是否存在。
  • 通过在 web.config 中包含以下内容,配置 ASP.NET 运行时将 WebApp.Web.Compilation.Runtime.ResourceFileHandler 用作 System.Web.IHttpHandler 来处理对此类文件的请求:
    <system.web>
        <httpHandlers>
            <add verb="*" path="*.html" 
                type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                                         WebApp.Web.Compilation.Runtime" />
            <add verb="*" path="*.css" 
                type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                                         WebApp.Web.Compilation.Runtime" />
            <add verb="*" path="*.js" 
                type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                                         WebApp.Web.Compilation.Runtime" />
            <add verb="*" path="*.gif" 
                type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                                         WebApp.Web.Compilation.Runtime" />
            <add verb="*" path="*.ico" 
                type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                                         WebApp.Web.Compilation.Runtime" />
            <add verb="*" path="*.png" 
                type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                                         WebApp.Web.Compilation.Runtime" />
            <add verb="*" path="*.bmp" 
                type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                                         WebApp.Web.Compilation.Runtime" />
            <add verb="*" path="*.jpg" 
                type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                                         WebApp.Web.Compilation.Runtime" />
            <add verb="*" path="*.jpeg" 
                type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                                         WebApp.Web.Compilation.Runtime" />
        </httpHandlers>
    </system.web>

    添加任何其他需要的文件名扩展名。

  • 通过在 web.config 中包含以下内容来配置 WebApp.Web.Compilation.Runtime.ResourceManager
    <configSections>
        <section name="WebApp.Web.Compilation.Runtime.ResourceManager" 
            type="System.Configuration.NameValueSectionHandler, 
            System, Version=1.0.5000.0, Culture=neutral, 
            PublicKeyToken=b77a5c561934e089"
            allowLocation="false" />
        <section name=
            "WebApp.Web.Compilation.Runtime.ResourceManager.ContentTypes" 
            type="System.Configuration.NameValueSectionHandler, 
            System, Version=1.0.5000.0, Culture=neutral, 
            PublicKeyToken=b77a5c561934e089"
            allowLocation="false" />
    </configSections>
    <WebApp.Web.Compilation.Runtime.ResourceManager>
        <add key="ResourceAssembly" value="UI" />
        <add key="CacheLoadedResources" value="false" />
        <add key="AllowExternalResources" value="false" />
        <add key="PreferExternalResources" value="false" />
        <add key="DefaultContentType" value="application/octet-stream" />
    </WebApp.Web.Compilation.Runtime.ResourceManager>
    <WebApp.Web.Compilation.Runtime.ResourceManager.ContentTypes>
        <add key="html" value="text/html" />
        <add key="css" value="text/css" />
        <add key="js" value="application/x-javascript" />
        <add key="gif" value="image/gif" />
        <add key="ico" value="image/x-icon" />
        <add key="png" value="image/png" />
        <add key="bmp" value="image/bmp" />
        <add key="jpg" value="image/jpeg" />
        <add key="jpeg" value="image/jpeg" />
    </WebApp.Web.Compilation.Runtime.ResourceManager.ContentTypes>

    这指定了包含资源的程序集、一些首选项以及应为每个扩展名在 HTTP 响应中返回的内容类型。

    您可以通过使用 WebApp.Web.Compilation.Runtime.ResourceManager.Init 方法和 WebApp.Web.Compilation.Runtime.ResourceManager.ContentTypes 字典来执行相同的操作。

简而言之,要使应用程序准备就绪,您需要在应用程序的 web.config 中包含以下内容:

<configuration>
    <configSections>
        <section name=
            "WebApp.Web.Compilation.Runtime.CompiledControlManager" 
            type="System.Configuration.NameValueSectionHandler, 
            System, Version=1.0.5000.0, Culture=neutral, 
            PublicKeyToken=b77a5c561934e089"
            allowLocation="false" />
        <section name=
            "WebApp.Web.Compilation.Runtime.ResourceManager" 
            type="System.Configuration.NameValueSectionHandler, 
            System, Version=1.0.5000.0, Culture=neutral, 
            PublicKeyToken=b77a5c561934e089"
            allowLocation="false" />
        <section name=
            "WebApp.Web.Compilation.Runtime.ResourceManager.ContentTypes" 
            type="System.Configuration.NameValueSectionHandler, 
            System, Version=1.0.5000.0, Culture=neutral, 
            PublicKeyToken=b77a5c561934e089"
            allowLocation="false" />
    </configSections>
    <WebApp.Web.Compilation.Runtime.CompiledControlManager>
        <add key="CompiledPageAssembly" value="UI" />
        <add key="CompiledUserControlAssembly" value="UI" />
        <add key="AllowNonCompiledPages" value="false" />
        <add key="AllowNonCompiledUserControls" value="false" />
    </WebApp.Web.Compilation.Runtime.CompiledControlManager>
    <WebApp.Web.Compilation.Runtime.ResourceManager>
        <add key="ResourceAssembly" value="UI" />
        <add key="CacheLoadedResources" value="false" />
        <add key="AllowExternalResources" value="false" />
        <add key="PreferExternalResources" value="false" />
        <add key="DefaultContentType" 
                           value="application/octet-stream" />
    </WebApp.Web.Compilation.Runtime.ResourceManager>
    <WebApp.Web.Compilation.Runtime.ResourceManager.ContentTypes>
        <add key="html" value="text/html" />
        <add key="css" value="text/css" />
        <add key="js" value="application/x-javascript" />
        <add key="gif" value="image/gif" />
        <add key="ico" value="image/x-icon" />
        <add key="png" value="image/png" />
        <add key="bmp" value="image/bmp" />
        <add key="jpg" value="image/jpeg" />
        <add key="jpeg" value="image/jpeg" />
    </WebApp.Web.Compilation.Runtime.ResourceManager.ContentTypes>
    <system.web>
      <httpHandlers>
        <add verb="*" path="*.aspx" 
          type="WebApp.Web.Compilation.Runtime.CompiledPageHandlerFactory,
                                         WebApp.Web.Compilation.Runtime" />
        <add verb="*" path="*.html" 
          type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                                         WebApp.Web.Compilation.Runtime" />
        <add verb="*" path="*.css" 
          type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                                         WebApp.Web.Compilation.Runtime" />
        <add verb="*" path="*.js" 
          type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                                         WebApp.Web.Compilation.Runtime" />
        <add verb="*" path="*.gif" 
          type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                                         WebApp.Web.Compilation.Runtime" />
        <add verb="*" path="*.ico" 
          type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                                         WebApp.Web.Compilation.Runtime" />
        <add verb="*" path="*.png" 
          type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                                         WebApp.Web.Compilation.Runtime" />
        <add verb="*" path="*.bmp" 
          type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                                         WebApp.Web.Compilation.Runtime" />
        <add verb="*" path="*.jpg" 
          type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                                         WebApp.Web.Compilation.Runtime" />
        <add verb="*" path="*.jpeg" 
          type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                                         WebApp.Web.Compilation.Runtime" />
      </httpHandlers>
    </system.web>
</configuration>

来调整这些设置,并在 IIS 管理控制台中设置扩展名。

在编译后的应用程序中将无法正常工作的项目?

如果用户控件是通过使用 WebApp.Web.Compilation.Runtime.CompiledControlManager.LoadControl 方法加载的,则对编译用户控件的缓存将不起作用。也就是说,如果您将 @OutputCache 指令或 System.Web.UI.PartialCachingAttribute 应用于已编译的用户控件,并且它不是直接在您的页面或用户控件中使用,而是通过 LoadControl 方法加载,则控件的缓存将不起作用。直接使用的页面和用户控件的缓存应该可以工作,但这未经测试。

编辑 2005-08-12:缓存现在可以工作了。源代码和演示项目已更新。

演示

演示是一个小的 ASP.NET C# 应用程序,演示了编译和资源嵌入的工作原理。其中包含有关如何编译和运行应用程序的简要说明,以及包含编译版本和生成的源代码的 .zip 文件。

许可证

WebApp.Web.Compilation 基于 GNU Lesser General Public License 获得许可(尽管运行应用程序不需要它),而 WebApp.Web.Compilation.Runtime 基于 MIT License(允许您对代码进行任何操作)。

最后说明

该解决方案已在一个相对较大的 ASP.NET 应用程序上进行了测试,并且运行正常。但是,有可能在生成源代码的过程中未能处理用户控件的所有使用模式,因此某些用户控件类型的名称在页面或用户控件中未得到修复。这可能会阻止源代码编译,如果未阻止 - 那是因为包含了已编译代码的自动生成的程序集。您可以通过检查程序集或测试应用程序部署后的运行情况来确保不存在此类引用。

© . All rights reserved.