预编译网站 (C#)

作者 :Scott Mitchell

Visual Studio 为 ASP.NET 开发人员提供了两种类型的项目:Web 应用程序项目 (WAP) 和网站项目 (WSP) 。 这两个项目类型之间的一个主要区别是,WAP 必须在部署之前显式编译代码,而 WSP 中的代码可以在 Web 服务器上自动编译。 但是,可以在部署之前预编译 WSP。 本教程探讨预编译的好处,并演示如何从 Visual Studio 和命令行预编译网站。

简介

Visual Studio 为 ASP.NET 开发人员提供了两种不同的项目类型:Web 应用程序项目 (WAP) 和网站项目 (WSP) 。 这些项目类型之间的主要区别之一是 WAP 需要 显式编译 ,而 WSP 默认使用 自动编译。 使用 WAP,可将 Web 应用程序的代码编译为在网站的 Bin 文件夹中创建的单个程序集。 部署需要复制 (项目中) 的 和 .master 文件以及文件夹中的程序集Bin的标记内容.aspx.ascx;无需部署代码隐藏类文件本身。 另一方面,通过将标记页及其相应的代码隐藏类复制到生产环境来部署 WSP。 代码隐藏类是在 Web 服务器上按需编译的。

注意

有关项目模型、显式编译和自动编译之间的差异以及编译模型如何影响部署的更多背景信息,请参阅 确定需要部署的文件 教程 中的“显式编译与自动编译”部分。

自动编译选项易于使用。 没有显式编译步骤,只需要部署已修改的文件,而显式编译需要部署更改的标记页和刚刚编译的程序集。 但是,自动部署有两个潜在的缺点:

  • 由于页面在首次访问时必须自动编译,因此在部署后首次请求 ASP.NET 页面时,可能会有短暂但明显的延迟。
  • 自动编译要求 Web 服务器上同时存在声明性标记和源代码。 如果你计划将 Web 应用程序销售给将在其 Web 服务器上安装该应用程序的客户,则这可以是一个没有吸引力的选项。

如果上述两个缺点之一是交易中断,则可以切换到 WAP 模型或在部署之前 预编译 WSP。 本教程介绍最适合托管网站的预编译选项,并演练预编译过程和预编译网站的部署。

ASP.NET 代码生成和编译概述

在查看可用的预编译选项之前,让我们先讨论一下在创建或上次更新后首次请求 ASP.NET 页时发生的代码生成和编译。 如你所知,ASP.NET 页由两部分组成:文件中的声明性标记 .aspx 和源代码部分,通常位于单独的代码隐藏类文件 (.aspx.cs) 。 请求 ASP.NET 页时运行时执行的步骤取决于应用程序的编译模型。

使用 WAP 时,必须先将页面的源代码显式编译为单个程序集,然后才能部署。 在部署期间,此程序集和各种标记页将复制到生产环境。 当请求到达 ASP.NET 页的 Web 服务器时,运行时会创建页面的代码隐藏类的实例,并调用其 ProcessRequest 方法,该方法启动页面生命周期,并最终生成页面的内容,该内容将返回到请求者。 运行时可以使用 ASP.NET 页的代码隐藏类,因为代码隐藏类已在部署之前编译为程序集。

使用 WSP 和自动编译,部署之前没有显式编译步骤。 相反,部署涉及将声明性内容和源代码内容复制到生产环境。 当创建或上次更新页面后第一次收到 ASP.NET 页的请求到达 Web 服务器时,运行时必须先将代码隐藏类编译为程序集。 此编译的程序集保存在 文件夹中%WINDIR%\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files,但此文件夹的位置可以通过 的 元素<system.web>进行自定义<compilation tempDirectory="" />,通常在 中Web.config。 由于程序集已保存到磁盘,因此不需要在后续请求到同一页时重新编译该程序集。

注意

正如你所料,首次 (或第一次请求页面时会略有延迟,因为在使用自动编译的站点中) 更改了页面,因为服务器编译页面代码并将生成的程序集保存到磁盘需要一些时间。

简言之,使用显式编译,需要在部署之前编译网站的源代码,使运行时不必执行此步骤。 使用自动编译,运行时处理页面源代码的编译,但自页面创建或上次更新后首次访问页面时,会花费少量的初始化成本。

但是,ASP.NET 页的声明性部分 (文件) .aspx 呢? 很明显,文件与其代码隐藏类中的代码之间存在 .aspx 关系,因为声明性标记中定义的 Web 控件可在代码中访问。 同样明显的是,文件中的内容 .aspx 对页面生成的呈现标记产生了很大的影响。 那么,运行时如何使用文件中定义的 .aspx 文本、HTML 和 Web 控件语法来生成所请求页面的呈现内容?

我不希望对低级别实现详细信息(WAP 和 WSP 而异)过于旁听,但简而言之,运行时会自动生成一个类文件,该文件包含各种 Web 控件作为受保护成员和方法。 此生成的文件作为 分部类 实现到相应的代码隐藏类。 (分部类 允许将单个类的内容分散到多个文件。) 因此,代码隐藏类在两个位置定义: .aspx.cs 在创建的文件中,以及运行时创建的自动生成的类中。 此自动生成的类存储在 %WINDIR%\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files 文件夹中。

此处的重要优势在于,对于运行时要呈现的 ASP.NET 页,其声明性和源代码部分都必须编译为程序集。 使用 WAP 时,源代码在部署之前显式编译为程序集,但声明性标记仍必须转换为代码并由 Web 服务器上的运行时编译。 使用自动编译的 WSP 时,源代码和声明性标记都需要由 Web 服务器编译。

可以通过 WSP 模型使用显式编译。 可以显式编译源代码部分,就像使用 WAP 模型一样。 此外,还可以编译声明性标记。

预编译选项

.NET Framework附带 ASP.NET 编译工具 (aspnet_compiler.exe) ,使你能够编译使用 WSP 模型生成的 ASP.NET 应用程序的源代码 (甚至内容) 。 此工具是随 .NET Framework 版本 2.0 一起发布的,位于 %WINDIR%\Microsoft.NET\Framework\v2.0.50727 文件夹中;它可从命令行使用,也可以通过“生成”菜单的“发布网站”选项从 Visual Studio 中启动。

编译工具提供两种常规的编译形式:就地预编译和部署预编译。 使用就地预编译,可从命令行运行 aspnet_compiler.exe 该工具,并指定驻留在计算机上的网站的虚拟目录或物理路径的路径。 然后,编译工具编译项目中的每个 ASP.NET 页,将编译的版本 %WINDIR%\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files 存储在 文件夹中,就像第一次从浏览器访问页面一样。 就地预编译可以加快对站点上新部署 ASP.NET 页面发出的第一个请求,因为它减轻了运行时执行此步骤的需要。 但是,就地预编译对大多数托管网站没有用,因为它要求你能够从 Web 服务器的命令行运行程序。 在共享托管环境中,不允许这种级别的访问。

注意

有关就地预编译的详细信息,请参阅如何:ASP.NET 2.0 中的预编译 ASP.NET 网站和预编译。

部署的预编译不会将网站中的页面编译到 Temporary ASP.NET Files 文件夹,而是以可部署到生产环境的格式将页面编译到所选的目录。

本教程将探讨两种用于部署的预编译:使用可更新的用户界面进行预编译,以及使用不可更新的用户界面进行预编译。 使用可更新用户界面的预编译会将声明性标记保留在 .aspx.ascx.master 文件中,从而允许开发人员在生产服务器上查看和修改声明性标记(如果需要)。 使用不可更新的用户界面进行预编译会 .aspx 生成任何内容无效的页面,并删除 .ascx.master 文件,从而隐藏声明性标记,并禁止开发人员在生产环境中对其进行更改。

使用可更新的用户界面进行部署的预编译

了解部署预编译的最佳方法是查看操作中的示例。 让我们使用可更新的用户界面预编译书评 WSP 进行部署。 可以从 Visual Studio 的“生成”菜单或命令行调用 ASP.NET 编译工具。 本部分介绍在 Visual Studio 中使用该工具;“从命令行预编译”部分查看从命令行运行编译器工具。

在 Visual Studio 中打开“书籍审阅 WSP”,转到“生成”菜单,然后选择“发布网站”菜单选项。 这将启动“发布网站”对话框, (请参阅 图 1) ,你可以在其中指定目标位置,无论预编译网站的用户界面是否可更新,以及其他编译器工具选项。 目标位置可以是远程 Web 服务器或 FTP 服务器,但现在请选择计算机硬盘驱动器上的文件夹。 由于我们希望使用可更新的用户界面预编译网站,因此请选中“允许此预编译的站点可更新”复选框并单击“确定”。

用于指定目标位置的“发布网站”对话框的屏幕截图。

图 1:ASP.NET 编译工具会将网站预编译到指定的目标位置
(单击以查看全尺寸图像)

注意

“生成”菜单中的“发布网站”选项在 Visual Web Developer 中不可用。 如果使用的是 Visual Web Developer,则需要使用 ASP.NET 编译工具的命令行版本,“从命令行进行预编译”部分对此进行了介绍。

预编译网站后,导航到在“发布网站”对话框中输入的目标位置。 花点时间将此文件夹的内容与网站内容进行比较。 图 2 显示了“书评”网站文件夹。 请注意,它同时 .aspx 包含 和 .aspx.cs 文件。 另请注意,该Bin目录仅包含一个文件 ,Elmah.dll我们在前面的教程中添加了该文件。

在“发布网站”对话框中输入的目标位置的屏幕截图,用于将此文件夹的内容与网站内容进行比较。

图 2:项目目录包含 .aspx.aspx.cs 文件; Bin 文件夹仅包含 Elmah.dll
(单击以查看全尺寸图像)

图 3 显示了 ASP.NET 编译工具创建其内容的目标位置文件夹。 此文件夹不包含任何代码隐藏文件。 此外,此文件夹的 Bin 目录包括多个程序集和两个 .compiled 文件,以及程序集 Elmah.dll

其内容由 A S P 创建的目标位置文件夹的屏幕截图。N E T 编译工具。

图 3:目标位置文件夹包括用于部署的文件
(单击以查看全尺寸图像)

与 WAP 中的显式编译不同,部署过程的预编译不会为整个站点创建一个程序集。 相反,它会将多个页面一起批处理到每个程序集中。 它还会将 Global.asax 文件 ((如果存在) )编译到其自己的程序集以及 文件夹中的任何类 App_Code 中。 分别保存 ASP.NET 网页、用户控件和母版页 (.aspx.ascx.master 文件的声明性标记的文件) 按原样复制到目标位置目录。 同样,文件 Web.config 与任何静态文件(如图像、CSS 类和 PDF 文件)一起直接复制。 有关编译工具如何处理各种文件类型的更正式说明,请参阅 ASP.NET 预编译期间的文件处理

注意

可以通过选中“发布网站”对话框中的“已使用固定命名和单页程序集”复选框,指示编译工具为每个 ASP.NET 页、用户控件或母版页创建一个程序集。 将每个 ASP.NET 页编译到其自己的程序集中,可以更精细地控制部署。 例如,如果更新了单个 ASP.NET 网页,并且需要部署该更改,则只需将页面 .aspx 的文件和关联的程序集部署到生产环境。 有关详细信息 ,请参阅如何:使用 ASP.NET 编译工具生成固定名称

目标位置目录还包含一个不属于预编译 Web 项目的文件,即 PrecompiledApp.config。 此文件通知 ASP.NET 运行时应用程序已预编译,以及它是使用可更新 UI 还是不可更新 UI 进行预编译。

最后,请花点时间使用 Visual Studio 或所选的文本编辑器打开目标位置中的一个 .aspx 文件。 使用可更新的用户界面预编译部署时,目标位置目录中的 ASP.NET 页面包含与网站中的相应文件完全相同的标记。

使用不可更新的用户界面进行部署的预编译

ASP.NET 编译器工具还可用于预编译站点,以便使用不可更新的 UI 进行部署。 使用不可更新的 UI 预编译网站的工作方式与使用可更新的 UI 进行预编译非常类似,主要区别在于,目标目录中的 ASP.NET 页、用户控件和母版页将去除其标记。 若要预编译网站以使用不可更新的 UI 进行部署,请从“生成”菜单中选择“发布网站”选项,但取消选中“允许此预编译站点可更新”选项 (请参阅 图 4) 。

“生成”菜单中“发布网站”选项的屏幕截图,用于预编译网站,以便使用不可更新的用户界面进行部署。

图 4:取消选中“允许此预编译站点可更新”选项以使用不可更新的 UI 进行预编译
(单击以查看全尺寸图像)

图 5 显示了使用不可更新的用户界面进行预编译后的目标位置文件夹。

使用不可更新的用户界面进行预编译后的目标位置文件夹的屏幕截图。

图 5:用于具有不可更新 UI 的部署的目标位置文件夹
(单击以查看全尺寸图像)

将图 3图 5 进行比较。 虽然这两个文件夹看起来可能完全相同,但请注意,不可更新的 UI 文件夹缺少母版页 Site.master。 虽然 图 5 包含各种 ASP.NET 页面,但如果查看这些文件的内容,你将看到它们已被删除其声明性标记并替换为占位符文本:“这是预编译工具生成的标记文件,不应删除!

A S P 的屏幕截图。从声明性标记中剥离并替换为占位符文本的 N E T 文件。

图 5:声明性标记已从 ASP.NET 页中删除

Bin图 3图 5 中的文件夹差异更大。 除了程序集,Bin图 5 中的 文件夹还包括.compiled每个 ASP.NET 页、用户控件和母版页的文件。

在不希望在生产环境中安装或管理网站的个人或公司修改 ASP.NET 页面内容的情况下,使用不可更新的 UI 预编译网站非常有用。 如果你构建了一个 ASP.NET Web 应用程序,该应用程序出售给客户以安装在他们自己的 Web 服务器上,你可能希望确保他们不会通过直接编辑 .aspx 你交付的页面来修改网站的外观。 通过使用不可更新的 UI 预编译网站,你可以在安装过程中交付占位符 .aspx 页面,从而阻止客户检查或修改其内容。

从命令行预编译

在后台,Visual Studio 的“发布网站”对话框调用 ASP.NET 编译工具 (aspnet_compiler.exe) 预编译网站。 或者,可以从命令行调用此工具。 事实上,如果使用 Visual Web Developer,则需要从命令行运行编译器工具,因为 Visual Web Developer 的“生成”菜单不包括“发布网站”选项。

若要从命令行使用编译器工具,请首先将 拖放到命令行并导航到框架目录 %WINDIR%\Microsoft.NET\Framework\v2.0.50727。 接下来,在命令行中输入以下语句:

aspnet_compiler -p "physical_path_to_app" -v / -f -u "target_location_folder"

上述命令 (aspnet_compiler.exe) 启动 ASP.NET 编译器工具, -p 并通过 开关指示它预编译根于 physical_path_to_app 的网站;此值类似于 C:\MySites\BookReviews,应用引号分隔。

开关 -v 指定站点的虚拟目录。 如果站点注册为 IIS 元数据库中的默认网站,则可以省略 -p 开关,只需指定应用程序的虚拟目录。 如果使用 -p 开关,则继续 -v 切换的值指示网站的根,并用于解析应用程序根引用。 例如,如果指定 值, -v /MySite 则应用程序中的 ~/path/file 引用将解析为 ~/MySite/path/file。 由于“书评”站点位于 Web 托管公司的根目录中,因此我使用了 开关 -v /

开关 -f (如果存在)指示编译工具覆盖 target_location_folder 目录(如果已存在)。 如果省略 -f 开关并且目标位置文件夹已存在,则编译工具将退出并显示错误:“错误 ASPRUNTIME:目标目录不为空。 请手动删除它或选择其他目标。”

开关 -u (如果存在)通知工具创建可更新的用户界面。 省略此开关以使用不可更新的用户界面预编译站点。

最后, target_location_folder 是目标位置目录的物理路径;此值类似于 C:\MySites\Output\BookReviews,应用引号分隔。

部署预编译网站

此时,我们已了解如何使用 ASP.NET 编译工具使用可更新和不可更新的用户界面选项来预编译网站。 但是,到目前为止,我们的示例已将网站预编译到本地文件夹,而不是生产环境。 好消息是,部署预编译的网站非常简单,可以通过 Visual Studio 或其他一些文件复制机制(例如从独立 FTP 客户端)完成。

“发布网站”对话框 (图 1 中首先显示) 有一个目标位置选项,该选项指示将预编译的网站文件复制到的位置。 此位置可以是远程 Web 服务器或 FTP 服务器。 将远程服务器输入到此文本框后,将网站预编译并部署到指定的服务器一步。 或者,可以将网站预编译到本地文件夹,然后通过 FTP 或其他某种方法手动将该文件夹的内容复制到生产环境。

通过 Visual Studio 的“发布网站”对话框自动部署预编译网站对于开发环境和生产环境之间没有配置差异的简单网站非常有用。 但是,如 开发和生产之间的常见配置差异 教程 中所述,这种差异并不少见。 例如,Book Reviews Web 应用程序在生产环境中使用的数据库与在开发环境中使用的数据库不同。 当 Visual Studio 将网站发布到远程服务器时,它会在开发环境中盲目复制配置文件信息。

对于在开发和生产环境之间具有配置差异的站点,最好将站点预编译到本地目录,复制特定于生产的配置文件,然后将预编译输出的内容复制到生产环境。

有关将文件从开发环境复制到生产环境的复习,请参阅 使用 FTP 客户端部署网站 和使用 Visual Studio 部署网站 教程。

总结

ASP.NET 支持两种编译模式:自动编译和显式编译模式。 如前面的教程中所述,Web 应用程序项目 (WAP) 使用显式编译,而网站项目 (WSP) 默认使用自动编译。 但是,可以在部署之前使用 ASP.NET 编译工具显式编译 WSP。

本教程重点介绍编译工具的预编译,以支持部署。 预编译进行部署时,编译工具会创建目标位置文件夹,编译指定的 Web 应用程序的源代码,并将这些编译的程序集和内容文件复制到目标位置文件夹中。 编译工具可以配置为创建可更新或不可更新的用户界面。 使用不可更新的用户界面选项进行预编译时,将删除内容文件中的声明性标记。 简而言之,预编译允许部署基于网站项目的应用程序,而无需包含任何源代码文件,并根据需要删除声明性标记。

编程愉快!

深入阅读

有关本教程中讨论的主题的详细信息,请参阅以下资源: