在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
show toc ASP.NET 2.0 的内部变化
原文出处:http://www.microsoft.com/china/msdn/library/webservices/asp.net/Internals.mspx 发布日期: Jayesh Patel、Bryan Acker 和 Robert McGovern Infusion Development 适用范围: Microsoft ASP.NET 2.0
摘要:尽管 ASP.NET 2.0 与 ASP.NET 1.1 完全向后兼容,但还是为 ASP.NET 带来了大量的内部变化,包括代码模型、编译、页面生命周期等的变化。本文将概括介绍这些变化。
本页内容 对于专业的 ASP.NET 开发人员来说,与 ASP.NET 2.0 有关的重要问题是内部发生了哪些变化。尽管新功能很有趣而且学起来很有意思,但对于真正想掌握这一技术的开发人员来说,ASP.NET 核心结构发生的变化才是最吸引他们的地方。在本白皮书中,我们将介绍自版本 1.x 以来,ASP.NET 2.0 内部结构发生了什么样的变化。 本白皮书介绍的主题对那些关注性能的开发人员以及寻求如何优化应用程序的技术设计师非常有用。具体来说,我们将介绍有关代码模型、编译、页面生命周期、可扩展性、性能和缓存的主要问题。 本文中的许多示例要求您对 ASP.NET、Visual Basic .NET 和/或 C# 语法有相当程度的了解。本文还在适当的地方提供了参考文档,就某些特定的主题展开深入的讨论。 也许 ASP.NET 2.0 内部工作方式最明显的变化是 ASP.NET Web 页面的创建方式的变化。本节将介绍内含代码模型发生的变化以及这些变化对 ASP.NET 开发的影响。 ASP.NET 1.x 中的代码模型 在 ASP.NET 1.x 中,供开发人员开发 Web 窗体的主要选择有两个。首先,开发人员可以参照传统的 ASP 模型并直接在 ASPX 页面中编写代码。此过程称为“内嵌代码”,它非常适用于简单的命令。然而,对于更复杂的代码而言,编写内嵌代码将为读取混合了表示 (HTML) 和功能(代码)的 Web 页面带来困难。在 ASP.NET 中,为了帮助解决这个问题,已更改了默认的编码方法。您可以在单独的、只包含代码的文件(称为“内含代码”文件)中编写业务逻辑和事件处理代码。内含代码模型将只包含代码的文件与包含表示标记的 ASPX 文件链接起来。通过将代码与表示相分离,开发小组可以让设计人员处理演示文件,而让开发人员处理代码文件,从而提高开发小组的工作效率。 图1:ASP.NET 1.x 代码模型 内含代码模型面临的主要困难在于如何将内含代码文件与 ASPX 页面保持同步。尽管从编程意义上来讲 ASPX 页面是从内含代码文件继承而来的,但实际上这两个文件是通过更复杂的关系联系在一起的。 有关 ASP.NET 1.x 中的内含代码模型的详细信息,请参见 MSDN Library 文章 Web Forms Code Model(英文)。 继承的复杂性 ASP.NET 的设计模式就是让开发人员使用 Microsoft Visual Studio .NET 将控件拖放到 ASPX 页面中。Visual Studio 然后将在内含代码文件中自动生成适当的支持代码。如果控件已被添加到 ASPX 页面中,则必须在内含代码文件中添加新代码。换句话说,尽管 ASPX 页面继承自内含代码文件,但实际上 ASPX 页面推动了内含代码文件的设计。 编译的复杂性 第二个同步问题就是如何编译文件。所有的内含代码文件以及所有的支持类都被编译到一个程序集中,并存储在 Web 应用程序的 /bin 目录中。应用程序的编译工作是在部署工作之前进行的。而另一方面,ASPX 页面也是在第一次被请求时在运行时编译的。ASP.NET 运行库实际上将 ASPX 页面编译到该页面自己的临时程序集中。 此过程的问题在于,无需更新内含代码程序集即可更改 ASPX 页面。也就是说,开发人员可以在部署后更改某个属性或更改 ASPX 页面上某个控件的类型,而无需更新内含代码文件,也不用重新编译应用程序的程序集。出现这种情况时,由于内含代码文件与所关联的 ASPX 页面不匹配,应用程序可能会遇到意外的错误。 ASP.NET 2.0 中的代码模型 ASP.NET 2.0 继续提供内嵌代码和内含代码模型。从内嵌代码模型的角度来说,除了 Microsoft Visual Studio 2005 支持单文件开发的方式有所变化外,基本上没做什么改动。有关 Visual Studio 2005 中的变化及其如何处理内嵌代码的详细信息,请参阅这篇文章(英文)。 ASP.NET 2.0 通过改变内含代码文件的本质解决了内含代码模型的继承和编译问题。在 ASP.NET 2.0 中,内含代码文件不再是 System.Web.UI.Page 类的完整实现。相反,内含代码文件是一个新的构造函数,称为“局部类”。局部类包含所有用户定义的代码,但是不包含 Visual Studio .NET 在 ASP.NET 1.x 中自动生成的任何管线和连接代码。请求包含新的内含代码文件的 ASPX 页面时,ASP.NET 2.0 运行库实际上将把 ASPX 页面和局部类合并成一个类,而不是两个单独的类。 图 2:ASP.NET 2.0 中的内含代码模型 局部类使用新的关键字(在 Visual Basic 中为 Expands,在 C# 中为 Partial)指示在运行时将该类中的代码与另一个类中的代码相合并。类似地,ASPX 页面使用新的指令(称为 compilewith)指示该页面与内含代码文件之间的关联。 比较内含代码文件 如果您熟悉传统的 ASP.NET 1.x 内含代码文件,您应该知道 Visual Studio 将插入自动生成的控件声明和初始化代码。这种自动生成的代码是内含代码文件与 ASPX 文件之间双向同步的直接结果。带有标签的典型 ASPX 页面具有一个对应的内含代码文件,该文件由许多自动生成的文本行构成。 列表 1:ASP.NET 1.x 中的内含代码文件 namespace WebApplication1 { public class WebForm1 :System.Web.UI.Page { protected System.Web.UI.WebControls.Label Label1; private void Page_Load(object sender, System.EventArgs e) { } #region Web Form Designer generated code override protected void OnInit(EventArgs e) { InitializeComponent(); base.OnInit(e); } private void InitializeComponent() { this.Load += new System.EventHandler(this.Page_Load); } #endregion } } 自动生成的代码不仅定义标签(以粗体显示的行),还声明新的事件(页面加载)并自动将该事件绑定到自动生成的方法包装程序 (Page_Load())。 比较而言,同一个 ASP.NET 页面在 ASP.NET 2.0 中生成的内含代码文件更简洁。 列表 2:ASP.NET 2.0.x 中的内含代码文件 namespace ASP { public partial class Webform1_aspx { } } 开发人员可以自动访问 Label1,并根据需要添加事件。例如,可以添加 Page_Load 事件以初始化标签。 列表 3:在新的内含代码文件中添加事件 namespace ASP { public partial class Webform1_aspx { void Page_Load(object sender, EventArgs e) { Label1.Text = "Hello ASP.NET 2.0"; } } } 事件语法可通过 Visual Studio .NET 生成。生成的内含代码文件更短,而且不包含任何自动生成的代码。ASP.NET 运行库会自动将内含代码文件中的事件绑定到 ASPX 页面上的控件。换句话说,ASP.NET 运行库现在可以自动执行代码生成,而这原本是由 Visual Studio 执行的。 继承的复杂性 新的内含代码模型大大降低了继承的复杂性。由于 ASPX 页面不是直接继承自内含代码文件,因此内含代码文件不再需要定义并支持 ASPX 页面上定义的所有控件。类似地,内含代码文件可以自动访问 ASPX 页面上的任何控件,而无需声明代码(声明代码在 ASP.NET 1.x 中是必需的)。这一切之所以能够实现,是因为 ASP.NET 运行库可以将所需的声明代码和事件绑定代码自动插入到最终编译的文件中。因为这些工作由运行库来完成,所以代码开发人员和 Web 开发人员都无需再担心这个问题。 在设计期间,链接将由 Visual Studio 2005 来维护。Visual Studio 环境将利用 ASP.NET 运行库编译段来确保代码开发人员和 Web 开发人员可以同步工作。 编译的复杂性 由于新的内含代码文件与 ASPX 页面链接在一起并在运行时被编译到一个完整的类中,因此编译的复杂性不复存在。也就是说,内含代码文件将自动与 ASPX 页面保持同步。即使新的编译模型也可能包含未同步的代码,但由于产生的异常非常清楚,因此可以快速找到问题的根源。 自从在 ASP.NET 1.x 中引入页面模型后,ASP.NET Web 页面的编译过程一直被分为两个阶段。首先,将内含代码文件和其他支持类编译到一个程序集中,然后在运行时编译各个 ASPX 文件。尽管此模型有很多优点,但它还有几个缺点。ASP.NET 2.0 为基本模型提供了几种替代方案,从而扩大了编译的选择范围,您可以根据特定需要进行选择。 ASP.NET 1.x 中的编译 ASP.NET 1.x 中的主要编译模型生成了一个应用程序程序集(包含所有已编译的内含代码文件和其他源代码)和一个临时程序集(专门为请求的每个 ASPX 页面而创建)。在某些情况下,编译器优化(例如批处理)可能会导致临时 ASPX 页面被编译到同一个程序集中。在任何情况下,都会将每个 ASPX 页面编译到一个临时程序集中,因此该页面可以加载到 ASP.NET 运行库中。 图 3:ASP.NET 1.x 中的编译 尽管此模型有很多优点,但它还有两个主要的缺点。首先,必须以用户可以阅读的格式将 ASPX 页面部署到 Web 站点上。如果开发人员使用“内嵌代码”模型,那么还需要将某些甚至所有业务逻辑部署到生产服务器上。尽管 IIS 和 ASP.NET 被配置为不显示原始 ASPX 页面,但是狡猾的攻击者仍然可以通过对 Web 服务器开放的任何入口访问这些文件。其次,任何人首次请求 Web 页面时,响应都会比正常情况下慢,因为 ASP.NET 运行库必须编译 ASPX 页面。 在这一过程中,开发人员唯一能够控制的就是是否对 ASPX 页面进行批编译。在 ASP.NET 1.x 中,您可以通过修改 web.config 文件中的 <compilation> 标记来配置批编译。 列表 4:配置批编译 <compilation batch="true|false" batchTimeout="number of seconds" maxBatchSize="maximum number of pages per batched compilation" maxBatchGeneratedFileSize="maximum combined size (in KB) of the generated source file per batched compilation" </compilation> 首次请求 Web 页面时,批编译将通过延长启动时间来缩短加载时间。批编译的另一个优点是将所有的 ASPX 文件编译到一个临时程序集中,而不是将每个页面编译到一个临时程序集中。 ASP.NET 2.0 中的编译 ASP.NET 2.0 为 Web 应用程序提供了四种不同的编译模型:
您可以根据实际的情况和需要选择最佳的编译选项,但编译模型仍然是灵活的。即使您选择使用代码目录来存储内含代码文件,也仍然可以使用完整编译这种方法来部署应用程序。 批编译 web.config 批编译设置在 ASP.NET 2.0 中仍然有效。批编译的优点在于,页面可以立即显示给第一个用户,并且可以在批编译过程中检测到 ASPX 页面中的任何错误。但是,批编译确实会延长应用程序的启动时间,而且必须内置在 web.config 文件中。 部署预编译 部署预编译允许您创建一个或多个程序集,作为 Web 站点的可执行版本。生成的程序集包含 Web 站点的已编译代码。HTML 页面、资源、配置文件和 ASPX 页面将被分别复制。 部署预编译需要使用 aspnet_compiler.exe 命令行实用程序,此实用程序将创建目标部署目录,其中包含用于存储程序集的 /bin 目录以及各种 ASPX 页面的 Stub 文件。还可以使用此实用程序执行在位预编译,与调用“魔术页面”的行为类似。Stub 文件使用 ASPX 页面的名称,但包含调用已编译程序集的简单代码。换句话说,ASPX 页面是简单的空壳,而不是功能完善的页面。 通过在部署之前预编译 Web 站点,安全性将大大提高,因为如果不对程序集进行反编译,将无法访问任何代码。为了增强保护,您可以打乱生成的程序集,使您的 Web 应用程序更安全。部署预编译的主要缺点在于您必须在部署之前完成这些操作,而且不能在部署后更改 Web 站点。如果要进行更改,必须重新编译 Web 站点并重新部署。 对于大多数主要的 Web 应用程序而言,部署预编译选项是实现部署的首选机制,因为它可以减少在 Web 服务器上部署的原始代码数量,并能提供最高的安全性。可以将增加的进程内置在通常的开发/测试/部署周期中,而不会严重降低工作效率。 在上述三种编译方法中,您必须在部署之前编译所有的代码文件(内含代码和支持类)。ASP.NET 2.0 中提供了代码目录。 代码目录是一个特殊的目录,用于存放未编译的类。在运行时,ASP.NET 运行库会将此目录中的内容编译到一个程序集中,该程序集将由应用程序中的 ASPX 页面自动引用。换句话说,使用代码目录,就无需为支持代码创建和引用单独的程序集。代码目录的优点在于,您无需完整地编译项目即可部署,从而降低了不匹配的可能性。但缺点是,您可能需要将未编译的代码存储在服务器上。 此选项特别适用于不需要大量支持代码(不管是以内含代码文件还是外部对象的格式)的 ASP.NET 应用程序。对于简单的应用程序而言,快速部署和测试系统的能力要比更稳健的编译方法更具优势。 ASP.NET 2.0 在 ASP.NET 页面的生命周期方面有两个主要的变化。首先,ASP.NET 2.0 提供了新的事件以支持新功能,这些功能包括母版页、个性化和集成的移动设备支持。其次,ASP.NET 2.0 引入了跨页发送 Web 窗体的技术。 新事件 与 ASP.NET 1.x 相比,ASP.NET 2.0 提供了更精确的页面生命周期方法堆栈。这些新增的方法为 Web 开发人员提供了更高级别的控制。可以通过任何 ASP.NET 页面上的“Page”对象访问这些事件。 表 1 显示了全面的方法列表。“方法”列显示了实际的事件方法名称,“活动”列指示事件是始终处于活动状态还是仅在 PostBack 操作期间处于活动状态。例如,可以使用新方法 TestDeviceFilter 来确定哪个设备筛选器可用,并使用此信息决定如何显示页面。换句话说,新方法 LoadControlState 仅在回发期间调用。可以替代此方法(与 SaveControlState 结合使用),以创建用于在回发期间保存和恢复控件状态的替换序列化方案。
通过查看页面生命周期的低级别详细信息,我们可以发现在何处能够自然地实现 ASP.NET 2.0 中的许多功能,例如主题和个性化。例如,可以在 IntializeThemes 事件中处理一个主题,在 LoadPersonalizationData 中加载个性化数据,并在以后应用于 ApplyPersonalization 方法。请注意,对于决定 Web 应用程序的最终外观的 UI 元素而言,方法的顺序极其重要。 跨页发送 页面生命周期的其他主要变化包括事件和 Web 窗体的回发。在 ASP.NET 1.x 中,Web 窗体是自动回发给其宿主页面的。也就是说,当用户提交窗体时,窗体数据将始终被提交回包含原始窗体的页面。这种设计可以很容易地存储控件状态,但限制了开发人员执行更复杂操作的能力。 在 ASP.NET 2.0 中,Web 窗体控件有一个新属性,使开发人员可以决定执行提交操作时将窗体数据发送到何处。大多数情况下都需要使用回发机制,因此该机制仍然是默认设置。但是,如果开发人员希望将数据发送到不同的窗体,现在这是可以实现的。 图 4:回发和跨页发送 例如,您可以创建一个多页面向导,其中包含几个不同的窗体。每个窗体按顺序提交给下一个页面,直到用户到达可以执行最终验证的摘要页面。可以在当前上下文中通过 PreviousPage 对象访问上一个页面上的数据。PreviousPage 对象用于存储上一个页面上经验证、可供在当前页面上使用的数据。正是因为有了这个对象,跨页发送才不会牺牲控件的持久性。如果用户需要按顺序备份一个窗体,可以立即访问这些页面数据,而不必重新输入所有数据。 ASP.NET 最初被设计成一个开放式框架。也就是说,构成 ASP.NET 的许多模块和组件都可以扩展、修改或替换以满足您的特定需要。在 ASP.NET 2.0 中,通过新的 HTTPHandlers 和 HTTPModules(现在是框架的标准组成部分)清楚地说明了框架的可扩展本质。 请求管道 在 ASP.NET 中,请求通过 Internet 服务器应用程序编程接口 (ISAPI) 筛选器从 Web 服务器传出,并传递给实际的 ASP.NET 运行库。 图 5:请求管道 当 IIS 接收到请求时,将根据 IIS 设置将扩展名映射到 ISAPI 筛选器。.aspx、.asmx、.asd 及其他扩展名被映射到 aspnet_isapi.dll,这只是一个用于启动 ASP.NET 运行库的 ISAPI 筛选器。当请求遇到 ASP.NET 运行库后,它将在 HTTPApplication 对象(作为 ASP.NET Web 应用程序的主机)上启动。HTTPApplication 对象:
在 ASP.NET 2.0 中,此模型没有任何变化,但添加了几个新的模块和处理程序以提供更多服务。就像在 ASP.NET 1.x 中一样,您可以扩展、替换或重新配置任何模块或处理程序类以提供自定义功能。 新模块 显然,新增的 HTTPModules 用于支持 ASP.NET 2.0 中提供的新服务。具体来说,具有默认模块设置的 ASP.NET 应用程序包括为以下目的而添加的新模块:
除了这些新模块以外,某些旧模块的行为也发生了变化:例如,输出缓存模块现在支持本白皮书后面介绍的新的缓存技术。 新处理程序 除了新模块以外,ASP.NET 2.0 还引入了新的处理程序,以支持应用程序配置工具和其他新功能,例如批编译请求。最重要的新处理程序包括用来处理 Web 站点管理请求的“.axd”系列。这些处理程序将启动允许开发人员配置 ASP.NET 用户和其他设置的内部管理工具。这些管理处理程序包括:
与以前一样,HTTPForbiddenHandler 被链接到不应返回的任何文件类型。在 ASP.NET 2.0 中,被禁止的文件类型列表已被扩展,现在包括母版页、外观文件及其他新的开发人员组件。 提高 Web 应用程序性能的一种方法是在内存中缓存静态内容。返回缓存的内容始终要比返回新渲染的内容快。但是,缺点是缓存的内容可能会过期。ASP.NET 1.x 支持几种缓存,包括:
在 ASP.NET 2.0 中,页面级别的缓存机制已得到扩展,以支持数据库依赖关系。借助数据库缓存依赖关系,可以将缓存的页面绑定到 SQL Server 数据库中的特定表。如果表发生变化,缓存将自动过期。此外,开发人员现在可以使用缓存后替换功能,用刷新的内容替换缓存的部分内容。缓存后替换功能允许应用程序使用页面级别的缓存,即使页面的部分内容应动态生成。 数据库缓存过期 对大多数数据驱动的 Web 站点来说,缓存是一个复杂的主题,特别是在需要缓存且必须更新数据的情况下。在 ASP.NET 1.x 中,页面可以缓存一段时间,并通过输入参数(查询字符串或 POST 参数)进行组织: 列表 5:ASP.NET 1.x 输出缓存指令 <%@ outputcache duration="3600" varybyparam="ProdID" %> 例如,列表 5 中的代码基于变量 ProdID 在内存中将页面缓存一小时。以上示例中出现的问题是,如果相关业务数据在其他地方被更新,应该怎么办?例如,假设按照产品 ID 缓存一个产品目录页面。如果从管理站点更新了此产品的相关信息(例如库存数量或价格),那么缓存的数据将不正确,显示给客户的数据也不正确。在以前版本的 ASP.NET 中,要解决此问题,需要使用 Response.RemoveOutputCacheItem 手动从缓存中删除该页面,或等到 duration 时间过期后让系统自动更新页面。 ASP.NET 2.0 通过支持数据库缓存依赖关系,从而解决了这一问题。使用 SQL Server 7 和 200 时可以使用表级别的通知,并且 Microsoft SQL Server 2005 将提供更精确级别的通知。例如,以下代码最多可以将产品页面缓存一小时,但添加了对数据库表的第二层依赖关系。 列表 6:ASP.NET 2.0 数据库缓存示例 <%@ outputcache duration="3600" varybyparam="ProdID" sqldependency="MyDatabase:Products" %> 使用新的 sqldependency 属性时,只要对“Products”表进行更改,缓存的页面就将过期。sqldependency 属性必须引用在 web.config 文件中配置的 datasource。datasource 用于标识数据库连接以及发出依赖关系通知所必需的参数。 自定义缓存依赖关系 ASP.NET 2.0 附带了一个 CacheDependency 实现,即 SQLCacheDependency 类,它支持 Microsoft SQL Server。实现新的缓存依赖关系是一个复杂的过程,但由于 ASP.NET 2.0 具有可扩展性,因此这一过程是可以实现的。换句话说,您可以创建自己的 CacheDependency 类,以便为其他数据库系统(如 Oracle 或 Sybase)提供类似的功能。 缓存后替换功能 对于几个页面元素保持动态更新,而页面的大部分内容适于缓存的情况,可以利用 ASP.NET 2.0 提供的缓存后替换功能。缓存后替换功能用于通知 ASP.NET 运行库是否应在向用户显示缓存的页面之前重新评估该页面上的某个特定元素。 使用此功能的方法有两种:
全部评论
专题导读
上一篇:asp.net如何做单元测试发布时间:2022-07-10下一篇:ADO.NET—Asp.net用DataSet对象更新数据(SqlDataAdapter)发布时间:2022-07-10热门推荐
热门话题
阅读排行榜
|
请发表评论