ASP.NET性能优化之编码篇

下面介绍如何在编码方面进行ASP.NET性能优化。

ASP.NET性能优化之页面和服务器控件处理

a)            避免到服务器的不必要的往返行程

在某些情况下不必使用 ASP.NET 服务器控件和执行回发事件处理。例如,在 ASP.NET 网页中验证用户输入经常可在数据提交到服务器之前在客户端进行。通常,如果不需要将信息传递到服务器以进行验证或将其写入数据存储区,请避免使用导致到服务器的往返行程的代码,这样可以提高页的性能并改善用户体验。您也可以不执行整个往返行程,而是使用客户端回调从服务器中读取数据。

页面类实现ICallbackEventHandler接口,注册GetCallbackEventReference方法,也就是ajax的回调实现。

针对一次需要载入很多控件的页面(载入比较耗时的页面),我们可以使用ajax技术来达到一定的页面访问性能提升。

b)            使用 Page 对象的 IsPostBack 属性来避免对往返行程执行不必要的处理

如果您编写处理服务器控件回发处理的代码,有时可能需要代码仅在首次请求页时执行,而不是每次回发时都执行。根据该页是否是响应服务器控件事件生成的,使用 IsPostBack 属性有条件地执行代码。

将仅需要首次请求页面时执行的代码放在IsPostBack条件中运行。

c)             只在必要时保存服务器控件视图状态

自动视图状态管理使服务器控件可以在往返行程中重新填充它们的属性值,而您不需要编写任何代码。但是,因为服务器控件的视图状态在隐藏的窗体字段中往返于服务器,所以该功能影响性能。了解在哪些情况下视图状态会有所帮助,在哪些情况下它影响页的性能,这样是有帮助的。例如,如果您将服务器控件绑定到每个往返行程上的数据,因为控件的值会在数据绑定期间用新值替换,所以保存的视图状态没有用处。在这种情况下,禁用视图状态可以节省处理时间并减少页的大小。

默认情况下,为所有服务器控件启用视图状态。若要禁用它,请将控件的 EnableViewState 属性设置为 false。

还可以使用 @ Page 指令禁用整个页的视图状态。当您不从页回发到服务器时,这将十分有用。

@ Control 指令中还支持 EnableViewState 属性以指定是否为用户控件启用视图状态。

查看视图状态的方法:

若要分析服务器控件在页中使用的视图状态的大小,请通过将 trace="true" 属性包含在 @ Page 指令中启用对该页的跟踪。然后在跟踪输出中,查看“控件层次结构”表的“Viewstate”列。

下面情况基本上可以禁用viewstate:

(1)页面控件 (.ascx)

(2)页面不回传给自身。

(3)无需对控件的事件处理。

(4)控件没有动态的或数据绑定的属性值(或对于每个postpack都在代码中处理)

d)            除非有特殊的原因要关闭缓冲,否则使其保持打开状态

禁用 ASP.NET 网页的缓冲会导致大量的性能开销。

e)            Server.Transfer和Response.Redirect的选择

Response.Redirect 简单地告诉浏览器访问另一个页面。Server.Transfer 有利于减少服务器请求,保持地址栏 URL 不变,允许你将 query string 和 form 变量传递到另一个页面,可以隐藏url中传递的参数。

Response.Redirect可以跨站点跳转,Server.Transfer只能同站点跳转。

微软建议:

使用 Transfer Server 对象或跨页发送的方法在同一个应用程序中的不同 ASP.NET 页之间重定向

如无特殊要求,应优先选择Server.Transfer进行页面跳转

ASP.NET性能优化之数据访问

a)            将 SQL Server 和存储过程用于数据访问

在 .NET Framework 提供的所有数据访问方法中,使用 SQL Server 进行数据访问是生成高性能、可缩放 Web 应用程序的推荐选择。使用托管 SQL Server 提供程序时,可通过尽可能使用编译的存储过程而不是 SQL 命令获得额外的性能提高。

(仅针对数据库选择SQL Server,数据库为其他的可以忽略此选项)

b)            将 SqlDataReader 类用于快速只进数据游标

SqlDataReader 类提供了从 SQL Server 数据库检索的只进数据流。如果您可以在 ASP.NET 应用程序中使用只读流,则 SqlDataReader 类提供比 DataSet 类更高的性能。SqlDataReader 类使用 SQL Server 的本机网络数据传输格式从数据库连接直接读取数据。例如,当绑定到 SqlDataSource 控件时,通过将 DataSourceMode 属性设置为 DataReader,您将获得更好的性能。(使用数据读取器会导致某些功能的丢失。)另外,SqlDataReader 类实现 IEnumerable 接口,该接口也使您可以将数据绑定到服务器控件。

(仅针对数据库选择SQL Server,数据库为其他的可以忽略此选项)   MySql中对应MySqlDataReader,根据需要选择。

c)             尽可能缓存数据和页输出

ASP.NET 提供了一些机制,它们会在不需要为每个页请求动态计算页输出或数据时缓存这些页输出或数据。另外,通过设计要进行缓存的页和数据请求(特别是在站点中预期将有较大通讯量的区域),可以优化这些页的性能。与使用 .NET Framework 的任何其他功能相比,适当地使用缓存可以更好地提高站点的性能。

在使用 ASP.NET 缓存时,应注意以下事项。首先,不要缓存太多项。缓存每个项都有内存开销。不要缓存容易重新计算和很少使用的项。其次,给缓存项分配的有效期不要太短。很快到期的项会导致缓存中不必要的周转,并且会导致额外的代码清除和垃圾回收工作。使用与“ASP.NET Applications”性能对象关联的“Cache Total Turnover Rate”(缓存总流通率)性能计数器,您可以监视缓存中由于项到期而导致的周转。高周转率可能说明存在问题,特别是当项在到期前被移除时。(这种情况有时称作内存压力。)

可以考虑把静态的、变化不大的或者不经常变化需要动态加载的内容放入控件中,使用缓存技术。

< %@ OutputCache Duration="100" VaryByParam="none" %>

d)            适当地使用 SQL 缓存依赖项

ASP.NET 同时支持基于表的轮询和查询通知,具体取决于所使用的 SQL Server 的版本。所有 SQL Server 版本都支持基于表的轮询。在基于表的轮询中,如果表中的任何内容发生更改,所有侦听器都会失效。这可能导致应用程序中不必要的改动。建议不要将基于表的轮询用于具有许多频繁更改的表。例如,建议将基于表的轮询用于很少更改的目录表。建议不要将基于表的轮询用于订单表,订单表具有更频繁的更新。SQL Server 2005 支持查询通知。查询通知支持特定查询,从而减少在表更改时发送的通知数量。虽然它比基于表的轮询提供更好的性能,但是它无法扩展到适应数千个查询。

(仅针对数据库选择SQL Server,数据库为其他的可以忽略此选项)

e)            使用数据源分页和排序而不是 UI(用户界面)分页和排序

DetailsView 和 GridView 等数据控件的 UI 分页功能可用于支持 ICollection 接口的任何数据源对象。对于每个分页操作,数据控件查询数据源的整个数据集并选择要显示的行,并放弃其余的数据。如果数据源实现 DataSourceView 并且 CanPage 属性返回 true,则数据控件将使用数据源分页而不是 UI 分页。在这种情况下,数据控件仅查询每个分页操作需要的行。因此,数据源分页比 UI 分页更高效。只有 ObjectDataSource 数据源控件才支持数据源分页。若要在其他数据源控件上启用数据源分页,必须从该数据源控件继承并修改其行为。

f)             平衡事件验证的安全性受益和性能开销

从 System.Web.UI.WebControls 和 System.Web.UI.HtmlControls 类派生的控件可以验证事件是否源自该控件所呈现的用户界面。这样有助于防止控件响应伪造的事件通知。例如,DetailsView 控件可以防止 Delete(删除)调用(控件中本质上不支持该调用)的处理以及被操纵而删除数据。此验证会带来一定的性能开销。可以使用 EnableEventValidation 配置元素和 RegisterForEventValidation 方法控制此行为。验证的开销取决于页上的控件数量,并在几个百分点范围内。

强烈建议不要禁用事件验证。在禁用事件验证之前,应该确保不会构造任何可能对应用程序具有意外影响的回发。

g)            除非必要,否则避免使用视图状态加密

视图状态加密会阻止用户能够读取隐藏视图状态字段中的值。典型情况是在 DataKeyNames 属性中带有一个标识符字段的 GridView 控件。标识符字段是协调对记录的更新所必需的。由于不想要标识符对用户可见,因此可以加密视图状态。但是,加密对于初始化具有恒定的性能开销,并具有取决于被加密的视图状态大小的附加开销。加密为每次页加载而设置,因此在每次页加载时都会发生相同的性能影响。

h)            使用 SqlDataSource 缓存、排序和筛选

如果 SqlDataSource 控件的 DataSourceMode 属性设置为 DataSet,则 SqlDataSource 能够缓存查询产生的结果集。如果以这种方式缓存数据,则控件的筛选和排序操作(使用 FilterExpression 和 SortParameterName 属性进行配置)将使用缓存的数据。在许多情况下,如果缓存整个数据集,并使用 FilterExpression 和 SortParameterName 属性进行排序和筛选,而不是使用带“WHERE”和“SORT BY”子句的 SQL 查询(对于这些查询,每个选择操作都要访问数据库),应用程序会运行得更快。

(根据具体控件,仅支持部分数据库)

ASP.NET性能优化之编码实践

a)            不要依赖代码中的异常

异常会大大地降低性能,所以您应该避免将它们用作控制正常程序流的方式。如果有可能检测到代码中可能导致异常的状态,请执行这种操作,而不要捕捉异常本身和处理该状态。常见的代码检测方案包括:检查 null,将一个值分配给将分析为数值的 String,或在应用数学运算前检查特定值。

b)            在托管代码中重写调用密集型的 COM 组件

.NET Framework 提供了一个简单的方法与传统的 COM 组件进行交互。其优点是可以在保留现有 COM 组件投资的同时利用 .NET 的功能。但是在某些情况下,保留旧组件的性能开销使得将组件迁移到托管代码是值得的。每一情况都是不一样的,决定是否需要迁移组件的最好方法是对网站运行性能测量。建议研究一下如何将经常调用的任何 COM 组件迁移到托管代码。

许多情况下不可能将旧式组件迁移到托管代码,特别是在最初迁移 Web 应用程序时。在这种情况下,最大的性能障碍之一是将数据从非托管环境封送到托管环境。因此,在交互操作中,请在任何一端执行尽可能多的任务,然后进行单个调用而不是一系列小调用。例如,公共语言运行库中的所有字符串都是 Unicode 的,所以应在调用托管代码之前将组件中的所有字符串转换成 Unicode 格式。

一旦处理完任何 COM 对象或本机资源就释放它们。这样,其他请求就能够使用它们,并且最大限度地减少了因稍后请求垃圾回收器释放它们所引起的性能问题。

c)             避免单线程单元 (STA) COM 组件

默认情况下,ASP.NET 不允许 STA COM 组件在页内运行。若要运行它们,必须在 .aspx 文件内将 ASPCompat=true 属性包含在 @ Page 指令中。这样就将页执行用的线程池切换到 STA 线程池,而且使 HttpContext 和其他内置对象可用于 COM 对象。避免使用 STA COM 组件是一种性能优化,因为它避免了将多线程单元 (MTA) 封送到 STA 线程的任何调用。

相关推荐