Fork me on GitHub
ASP.NET中常用的优化性能方法

1. 数据库访问性能优化 
 
数据库的连接和关闭

 

访问数据库资源需要创建连接、打开连接和关闭连接几个操作。这些过程需要多次与数据库交换信息以通过身份验证,比较耗费服务器资源。ASP.NET中提供了连接池(Connection Pool)改善打开和关闭数据库对性能的影响。系统将用户的数据库连接放在连接池中,需要时取出,关闭时收回连接,等待下一次的连接请求。连接池的大小是有限的,如果在连接池达到最大限度后仍要求创建连接,必然大大影响性能。因此,在建立数据库连接后只有在真正需要操作时才打开连接,使用完毕后马上关闭,从而尽量减少数据库连接打开的时间,避免出现超出连接限制的情况。   

使用存储过程  
 
存储过程是存储在服务器上的一组预编译的SQL语句,类似于DOS系统中的批处理文件。存储过程具有对数据库立即访问的功能,信息处理极为迅速。使用存储过程可以避免对命令的多次编译,在执行一次后其执行规划就驻留在高速缓存中,以后需要时只需直接调用缓存中的二进制代码即可。另外,存储过程在服务器端运行,独立于ASP.NET程序,便于修改,最重要的是它可以减少数据库操作语句在网络中的传输。

优化查询语句
  
ASP.NET中ADO连接消耗的资源相当大,SQL语句运行的时间越长,占用系统资源的时间也越长。因此,尽量使用优化过的SQL语句以减少执行时间。比如,不在查询语句中包含子查询语句,充分利用索引等。   

2. 字符串操作性能优化 
 
使用值类型的ToString方法
  
在连接字符串时,经常使用"+"号直接将数字添加到字符串中。这种方法虽然简单,也可以得到正确结果,但是由于涉及到不同的数据类型,数字需要通过装箱操作转化为引用类型才可以添加到字符串中。但是装箱操作对性能影响较大,因为在进行这类处理时,将在托管堆中分配一个新的对象,原有的值复制到新创建的对象中。使用值类型的ToString方法可以避免装箱操作,从而提高应用程序性能。   

运用StringBuilder类   

String类对象是不可改变的,对于String对象的重新赋值在本质上是重新创建了一个String对象并将新值赋予该对象,其方法ToString对性能的提高并非很显著。在处理字符串时,最好使用StringBuilder类,其.NET 命名空间是System.Text。该类并非创建新的对象,而是通过Append,Remove,Insert等方法直接对字符串进行操作,通过ToString方法返回操作结果。   其定义及操作语句如下所示:


int num;   System.Text.StringBuilder str = new System.Text.StringBuilder(); //创建字符串   str.Append(num.ToString()); //添加数值num   Response.Write(str.ToString); //显示操作结果3. 优化 Web 服务器计算机和特定应用程序的配置文件以符合您的特定需要

默认情况下,ASP.NET 配置被设置成启用最广泛的功能并尽量适应最常见的方案。因此,应用程序开发人员可以根据应用程序所使用的功能,优化和更改其中的某些配置,以提高应用程序的性能。下面的列表是您应该考虑的一些选项。

仅对需要的应用程序启用身份验证。

默认情况下,身份验证模式为 Windows,或集成 NTLM。大多数情况下,对于需要身份验证的应用程序,最好在 Machine.config 文件中禁用身份验证,并在 Web.config 文件中启用身份验证。根据适当的请求和响应编码设置来配置应用程序。ASP.NET 默认编码格式为 UTF-8。如果您的应用程序为严格的 ASCII,请配置应用程序使用 ASCII 以获得稍许的性能提高。
  
考虑对应用程序禁用 AutoEventWireup。

在 Machine.config 文件中将 AutoEventWireup 属性设置为 false,意味着页面不将方法名与事件进行匹配和将两者挂钩(例如 Page_Load)。如果页面开发人员要使用这些事件,需要在基类中重写这些方法(例如,需要为页面加载事件重写 Page.OnLoad,而不是使用 Page_Load 方法)。如果禁用 AutoEventWireup,页面将通过将事件连接留给页面作者而不是自动执行它,获得稍许的性能提升。

从请求处理管线中移除不用的模块。

默认情况下,服务器计算机的 Machine.config 文件中 节点的所有功能均保留为激活。根据应用程序所使用的功能,您可以从请求管线中移除不用的模块以获得稍许的性能提升。检查每个模块及其功能,并按您的需要自定义它。例如,如果您在应用程序中不使用会话状态和输出缓存,则可以从 列表中移除它们,以便请求在不执行其他有意义的处理时,不必执行每个模块的进入和离开代码。

4. 一定要禁用调试模式  

在部署生产应用程序或进行任何性能测量之前,始终记住禁用调试模式。如果启用了调试模式,应用程序的性能可能受到非常大的影响。   

5. 对于广泛依赖外部资源的应用程序,请考虑在多处理器计算机上启用网络园艺  

ASP.NET 进程模型帮助启用多处理器计算机上的可缩放性,将工作分发给多个进程(每个CPU一个),并且每个进程都将处理器关系设置为其 CPU。此技术称为网络园艺。如果应用程序使用较慢的数据库服务器或调用具有外部依赖项的 COM 对象(这里只是提及两种可能性),则为您的应用程序启用网络园艺是有益的。但是,在决定启用网络园艺之前,您应该测试应用程序在网络园中的执行情况。   

6. 只要可能,就缓存数据和页输出  

ASP.NET 提供了一些简单的机制,它们会在不需要为每个页请求动态计算页输出或数据时缓存这些页输出或数据。另外,通过设计要进行缓存的页和数据请求(特别是在站点中预期将有较大通讯量的区域),可以优化这些页的性能。与 .NET Framework 的任何 Web 窗体功能相比,适当地使用缓存可以更好的提高站点的性能,有时这种提高是超数量级的。使用 ASP.NET 缓存机制有两点需要注意。首先,不要缓存太多项。缓存每个项均有开销,特别是在内存使用方面。不要缓存容易重新计算和很少使用的项。其次,给缓存的项分配的有效期不要太短。很快到期的项会导致缓存中不必要的周转,并且经常导致更多的代码清除和垃圾回收工作。若关心此问题,请监视与 ASP.NET Applications 性能对象关联的 Cache Total Turnover Rate 性能计数器。高周转率可能说明存在问题,特别是当项在到期前被移除时。这也称作内存压力。


7. 选择适合页面或应用程序的数据查看机制  

根据您选择在 Web 窗体页显示数据的方式,在便利和性能之间常常存在着重要的权衡。例如,DataGrid Web 服务器控件可能是一种显示数据的方便快捷的方法,但就性能而言它的开销常常是最大的。在某些简单的情况下,您通过生成适当的 HTML 自己呈现数据可能很有效,但是自定义和浏览器定向会很快抵销所获得的额外功效。Repeater Web 服务器控件是便利和性能的折衷。它高效、可自定义且可编程。   

8. 将 SqlDataReader 类用于快速只进数据游标  

SqlDataReader 类提供了一种读取从 SQL Server 数据库检索的只进数据流的方法。如果当创建 ASP.NET 应用程序时出现允许您使用它的情况,则 SqlDataReader 类提供比 DataSet 类更高的性能。情况之所以这样,是因为 SqlDataReader 使用 SQL Server 的本机网络数据传输格式从数据库连接直接读取数据。另外,SqlDataReader 类实现 IEnumerable 接口,该接口也允许您将数据绑定到服务器控件。有关更多信息,请参见 SqlDataReader 类。有关 ASP.NET 如何访问数据的信息,请参见通过 ASP.NET 访问数据。   

9. 将 SQL Server 存储过程用于数据访问  

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

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

默认情况下,ASP.NET 不允许任何 STA COM 组件在页面内运行。若要运行它们,必须在 .aspx 文件内将 ASPCompat=true 属性包含在 @ Page 指令中。这样就将执行用的线程池切换到 STA 线程池,而且使 HttpContext 和其他内置对象可用于 COM 对象。前者也是一种性能优化,因为它避免了将多线程单元 (MTA) 封送到 STA 线程的任何调用。使用 STA COM 组件可能大大损害性能,应尽量避免。若必须使用 STA COM 组件,如在任何 interop 方案中,则应在执行期间进行大量调用并在每次调用期间发送尽可能多的信息。另外,小心不要在构造页面期间创建任何 STA COM 组件。例如下面的代码中,在页面构造时将实例化由某个线程创建的 MySTAComponent,而该线程并不是将运行页面的 STA 线程。这可能对性能有不利影响,因为要构造页面就必须完成 MTA 和 STA 线程之间的封送处理。


Dim myComp as new MySTAComponent() Public Sub Page_Load() myComp.Name = "Bob" End Sub


首选机制是推迟对象的创建,直到以后在 STA 线程下执行上述代码,如下面的例子所示。

 


Dim myComp Public Sub Page_Load() myComp = new MySTAComponent() myComp.Name = "Bob" End Sub

推荐的做法是在需要时或者在 Page_Load 方法中构造任何 COM 组件和外部资源。永远不要将任何 STA COM 组件存储在可以由构造它的线程以外的其他线程访问的共享资源里。这类资源包括像缓存和会话状态这样的资源。即使 STA 线程调用 STA COM 组件,也只有构造此 STA COM 组件的线程能够实际为该调用服务,而这要求封送处理对创建者线程的调用。此封送处理可能产生重大的性能损失和可伸缩性问题。在这种情况下,请研究一下使 COM 组件成为 MTA COM 组件的可能性,或者更好的办法是迁移代码以使对象成为托管对象。   

11. 将调用密集型的 COM 组件迁移到托管代码  

.NET Framework 提供了一个简单的方法与传统的 COM 组件进行交互。其优点是可以在保留现有投资的同时利用新的平台。但是在某些情况下,保留旧组件的性能开销使得将组件迁移到托管代码是值得的。每一情况都是不一样的,决定是否需要迁移组件的最好方法是对 Web 站点运行性能测量。建议您研究一下如何将需要大量调用以进行交互的任何COM 组件迁移到托管代码。许多情况下不可能将旧式组件迁移到托管代码,特别是在最初迁移 Web 应用程序时。在这种情况下,最大的性能障碍之一是将数据从非托管环境封送到托管环境。因此,在交互操作中,请在任何一端执行尽可能多的任务,然后进行一个大调用而不是一系列小调用。例如,公共语言运行库中的所有字符串都是 Unicode 的,所以应在调用托管代码之前将组件中的所有字符串转换成 Unicode 格式。另外,一处理完任何 COM 对象或本机资源就释放它们。这样,其他请求就能够使用它们,并且最大限度地减少了因稍后请求垃圾回收器释放它们所引起的性能问题。   

12. 在 Visual Basic .NET 或 JScript. 代码中使用早期绑定  

以往,开发人员喜欢使用 Visual Basic、VBScript. 和 JScript. 的原因之一就是它们所谓“无类型”的性质。变量不需要显式类型声明,并能够简单地通过使用来创建它们。当从一个类型到另一个类型进行分配时,转换将自动执行。不过,这种便利会大大损害应用程序的性能。Visual Basic 现在通过使用 Option Strict 编译器指令来支持类型安全编程。为了向后兼容,默认情况下,ASP.NET 不启用该选项。但是,为了得到最佳性能,强烈建议在页中启用该选项。若要启用 Option Strict,请将 Strict 属性包括在 @ Page 指令中,或者,对于用户控件,请将该属性包括在 @ Control 指令中。下面的示例演示了如何设置该属性,并进行了四个变量调用以显示使用该属性是如何导致编译器错误的。

JScript. .NET 也支持无类型编程,但它不提供强制早期绑定的编译器指令。若发生下面任何一种情况,则变量是晚期绑定的:被显式声明为 Object,是无类型声明的类的字段,是无显式类型声明的专用函数或方法成员,并且无法从其使用推断出类型。   最后一个差别比较复杂,因为如果 JScript. .NET 编译器可以根据变量的使用情况推断出类型,它就会进行优化。在下面的示例中,变量 A 是早期绑定的,但变量 B 是晚期绑定的。

var A;   var B;   A = "Hello";   B = "World";   B = 0; 为了获得最佳的性能,当声明 JScript. .NET 变量时,请为其分配一个类型。例如,var A : String。

13. 使请求管线内的所有模块尽可能高效  

请求管线内的所有模块在每次请求中都有机会被运行。因此,当请求进入和离开模块时快速地触发代码至关重要,特别是在不使用模块功能的代码路径里。分别在使用及不使用模块和配置文件时执行吞吐量测试,对确定这些方法的执行速度非常有用。

14. 使用 HttpServerUtility.Transfer 方法在同一应用程序的页面间重定向  

采用 Server.Transfer 语法,在页面中使用该方法可避免不必要的客户端重定向。
  
15. 必要时调整应用程序每个辅助进程的线程数  

ASP.NET 的请求结构试图在执行请求的线程数和可用资源之间达到一种平衡。已知一个使用足够 CPU 功率的应用程序,该结构将根据可用于请求的 CPU 功率,来决定允许同时执行的请求数。这项技术称作线程门控。但是在某些条件下,线程门控算法不是很有效。通过使用与 ASP.NET Applications 性能对象关联的 Pipeline Instance Count 性能计数器,可以在 PerfMon 中监视线程门控。当页面调用外部资源,如数据库访问或 XML Web services 请求时,页面请求通常停止并释放 CPU。如果某个请求正在等待被处理,并且线程池中有一个线程是自由的,那么这个正在等待的请求将开始被处理。遗憾的是,有时这可能导致 Web 服务器上存在大量同时处理的请求和许多正在等待的线程,而它们对服务器性能有不利影响。通常,如果门控因子是外部资源的响应时间,则让过多请求等待资源,对 Web 服务器的吞吐量并无帮助。为缓和这种情况,可以通过更改 Machine.config 配置文件节点的 maxWorkerThreads 和 maxIOThreads 属性,手动设置进程中的线程数限制。   

注意:辅助线程是用来处理 ASP.NET 请求的,而 IO 线程则是用于为来自文件、数据库或 XML Web services 的数据提供服务的。分配给这些属性的值是进程中每个 CPU 每类线程的最大数目。对于双处理器计算机,最大数是设置值的两倍。对于四处理器计算机,最大值是设置值的四倍。无论如何,对于有四个或八个 CPU 的计算机,最好更改默认值。对于有一个或两个处理器的计算机,默认值就可以,但对于有更多处理器的计算机的性能,进程中有一百或两百个线程则弊大于利。注意进程中有太多线程往往会降低服务器的速度,因为额外的上下文交换导致操作系统将 CPU 周期花在维护线程而不是处理请求上。   

16. 适当地使用公共语言运行库的垃圾回收器和自动内存管理  

小心不要给每个请求分配过多内存,因为这样垃圾回收器将必须更频繁地进行更多的工作。另外,不要让不必要的指针指向对象,因为它们将使对象保持活动状态,并且应尽量避免含 Finalize 方法的对象,因为它们在后面会导致更多的工作。特别是在 Finalize 调用中永远不要释放资源,因为资源在被垃圾回收器回收之前可能一直消耗着内存。最后这个问题经常会对 Web 服务器环境的性能造成毁灭性的打击,因为在等待 Finalize 运行时,很容易耗尽某个特定的资源。   

17. 如果有大型 Web 应用程序,可考虑执行预批编译  

每当发生对目录的第一次请求时都会执行批编译。如果目录中的页面没有被分析并编译,此功能会成批分析并编译目录中的所有页面,以便更好地利用磁盘和内存。如果这需要很长时间,则将快速分析并编译单个页面,以便请求能被处理。此功能带给 ASP.NET 性能上的好处,因为它将许多页面编译为单个程序集。从已加载的程序集访问一页比每页加载新的程序集要快。批编译的缺点在于:如果服务器接收到许多对尚未编译的页面的请求,那么当 Web 服务器分析并编译它们时,性能可能较差。为解决这个问题,可以执行预批编译。为此,只需在应用程序激活之前向它请求一个页面,无论哪页均可。然后,当用户首次访问您的站点时,页面及其程序集将已被编译。没有简单的机制可以知道批编译何时发生。需一直等到 CPU 空闲或者没有更多的编译器进程(例如 csc.exe(C# 编译器)或 vbc.exe(Visual Basic 编译器))启动。还应尽量避免更改应用程序的 \bin 目录中的程序集。更改页面会导致重新分析和编译该页,而替换 \bin 目录中的程序集则会导致完全重新批编译该目录。在包含许多页面的大规模站点上,更好的办法可能是根据计划替换页面或程序集的频繁程度来设计不同的目录结构。不常更改的页面可以存储在同一目录中并在特定的时间进行预批编译。经常更改的页面应在它们自己的目录中(每个目录最多几百页)以便快速编译。Web 应用程序可以包含许多子目录。批编译发生在目录级,而不是应用程序级。

18. 不要依赖代码中的异常  

因为异常大大地降低性能,所以您不应该将它们用作控制正常程序流程的方式。如果有可能检测到代码中可能导致异常的状态,请执行这种操作。不要在处理该状态之前捕获异常本身。常见的方案包括:检查 null,分配给将分析为数字值的 String 一个值,或在应用数学运算前检查特定值。下面的示例演示可能导致异常的代码以及测试是否存在某种状态的代码。两者产生相同的结果。


 try   {   result = 100 / num;   }   catch (Exception e)   {   result = 0;   }   // ...to this.   if (num != 0)   result = 100 / num;   else   result = 0;

19. 使用 HttpResponse.Write 方法进行字符串串联

该方法提供非常有效的缓冲和连接服务。但是,如果您正在执行广泛的连接,请使用多个 Response.Write 调用。下面示例中显示的技术比用对 Response.Write 方法的单个调用连接字符串更快。

 


Response.Write("a");   Response.Write(myString);   Response.Write("b");   Response.Write(myObj.ToString());   Response.Write("c");   Response.Write(myString2);   Response.Write("d"); 20. 除非有特殊的原因要关闭缓冲,否则使其保持打开

禁用 Web 窗体页的缓冲会导致大量的性能开销。   

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

自动视图状态管理是服务器控件的功能,该功能使服务器控件可以在往返过程上重新填充它们的属性值(您不需要编写任何代码)。但是,因为服务器控件的视图状态在隐藏的窗体字段中往返于服务器,所以该功能确实会对性能产生影响。您应该知道在哪些情况下视图状态会有所帮助,在哪些情况下它影响页的性能。例如,如果您将服务器控件绑定到每个往返过程上的数据,则将用从数据绑定操作获得的新值替换保存的视图状态。在这种情况下,禁用视图状态可以节省处理时间。默认情况下,为所有服务器控件启用视图状态。若要禁用视图状态,请将控件的EnableViewState 属性设置为 false,如下面的 DataGrid 服务器控件示例所示。

 


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

 


注意Angry Control 指令中也支持 EnableViewState 属性,该指令允许您控制是否为用户控件启用视图状态。若要分析页上服务器控件使用的视图状态的数量,请(通过将 trace="true" 属性包括在 @ Page 指令中)启用该页的跟踪并查看 Control Hierarchy 表的 Viewstate 列。有关跟踪和如何启用它的信息,请参见 ASP.NET 跟踪。

22. 避免到服务器的不必要的往返过程  

虽然您很可能希望尽量多地使用 Web 窗体页框架的那些节省时间和代码的功能,但在某些情况下却不宜使用 ASP.NET 服务器控件和回发事件处理。通常,只有在检索或存储数据时,您才需要启动到服务器的往返过程。多数数据操作可在这些往返过程间的客户端上进行。例如,从 HTML 窗体验证用户输入经常可在数据提交到服务器之前在客户端进行。通常,如果不需要将信息传递到服务器以将其存储在数据库中,那么您不应该编写导致往返过程的代码。如果您开发自定义服务器控件,请考虑让它们为支持 ECMAScript. 的浏览器呈现客户端代码。通过以这种方式使用服务器控件,您可以显著地减少信息被不必要的发送到 Web 服务器的次数。

使用 Page.IsPostBack 避免对往返过程执行不必要的处理

如果您编写处理服务器控件回发处理的代码,有时可能需要在首次请求页时执行其他代码,而不是当用户发送包含在该页中的 HTML 窗体时执行的代码。根据该页是否是响应服务器控件事件生成的。

使用 Page.IsPostBack 属性有条件地执行代码

例如,下面的代码演示如何创建数据库连接和命令,该命令在首次请求该页时将数据绑定到 DataGrid 服务器控件。


void Page_Load(Object sender, EventArgs e)   {   // Set up a connection and command here.   if (!Page.IsPostBack)   {   String query = "select * from Authors where FirstName like '%JUSTIN%'";   myCommand.Fill(ds, "Authors");   myDataGrid.DataBind();   }   }

由于每次请求时都执行 Page_Load 事件,上述代码检查 IsPostBack 属性是否设置为 false。如果是,则执行代码。如果该属性设置为 true,则不执行代码。注意 如果不运行这种检查,回发页的行为将不更改。Page_Load 事件的代码在执行服务器控件事件之前执行,但只有服务器控件事件的结果才可能在输出页上呈现。如果不运行该检查,仍将为 Page_Load 事件和该页上的任何服务器控件事件执行处理。   

23. 当不使用会话状态时禁用它  

并不是所有的应用程序或页都需要针对于具体用户的会话状态,您应该对任何不需要会话状态的应用程序或页禁用会话状态。   若要禁用页的会话状态,请将 @ Page 指令中的 EnableSessionState 属性设置为 false。例如:

 

注意:如果页需要访问会话变量,但不打算创建或修改它们,则将@ Page 指令中的 EnableSessionState 属性设置为ReadOnly。还可以禁用 XML Web services 方法的会话状态。有关更多信息,请参见使用 ASP.NET 和 XML Web services 客户端创建的 XML Web services。若要禁用应用程序的会话状态,请在应用程序 Web.config 文件的 sessionstate 配置节中将 mode 属性设置为 off。例如:

 

24. 仔细选择会话状态提供程序  

ASP.NET 为存储应用程序的会话数据提供了三种不同的方法:进程内会话状态、作为 Windows 服务的进程外会话状态和 SQL Server 数据库中的进程外会话状态。每种方法都有自己的优点,但进程内会话状态是迄今为止速度最快的解决方案。如果只在会话状态中存储少量易失数据,则建议您使用进程内提供程序。进程外解决方案主要用于跨多个处理器或多个计算机缩放应用程序,或者用于服务器或进程重新启动时不能丢失数据的情况。有关更多信息,请参见 ASP.NET 状态管理。   

25. 不使用不必要的Server Control

ASP.net中,大量的服务器端控件方便了程序开发,但也可能带来性能的损失,因为用户每操作一次服务器端控件,就产生一次与服务器端的往返过程。因此,非必要,应当少使用Server Control。   

26. ASP.NET应用程序性能测试  

在对ASP.NET应用程序进行性能测试之前,应确保应用程序没有错误,而且功能正确。具体的性能测试可以采用以下工具进行:Web Application Strees Tool (WAS)是Microsoft发布的一个免费测试工具,可以从http://webtool.rte.microsoft.com/上下载。它可以模拟成百上千个用户同时对web应用程序进行访问请求,在服务器上形成流量负载,从而达到测试的目的,可以生成平均TTFB、平均TTLB等性能汇总报告。Application Center Test (ACT) 是一个测试工具,附带于Visual Studio.NET的企业版中,是Microsoft正式支持的web应用程序测试工具。它能够直观地生成图表结果,功能比WAS多,但不具备多个客户机同时测试的能力。服务器操作系统"管理工具"中的"性能"计数器,可以对服务器进行监测以了解应用程序性能。   

结论:

 

 

 

 

 

 

对于网站开发人员来说,在编写ASP.NET应用程序时注意性能问题,养成良好的习惯,提高应用程序性能,至少可以推迟必需的硬件升级,降低网站的成本。

提高ASP.Net应用程序性能的十大方法(一)

 

 

  现在写一个asp.net的web应用程序变得非常的简单,许多的程序员都不愿花时间去构建一个性能良好的应用程序。本文将要讨论提高web应用程序性能的十大方法。我将不限于只讨论asp.net应用程序的内容,因为它们只是web应用程序的一个子集。本文也不能提供一个完整提高web应用程序性能的指南,因为这需要一本书的篇幅。本文只提供一个提高web应用程序性能的良好的开端。(剩下的只有我们自己慢慢研究了)。
  在工作这外,我经常去攀岩,在每次攀岩之前,我都会重温一下攀岩线路图及看一下前面的成功的攀岩者的建议。因为我们需要它们的成功经验。同样的,当你需要修改某个有性能问题的程序或者是要开发一个高性能的站点时,你也需要学习怎么样写一个高性能的web应用程序。
  我个人的经验主要来源于在微软的asp.net组担任程序经理,运行和管理www.asp.net网站,和协助开发Community Server(它是asp.net Forums,.Text, and nGallery的集成升级版本软件)。我想这些经验能我让来帮助大家。
  你也许会想到把你的应用程序划分成不同的逻辑层。你也可能听过三层物理架构或N层架构,这是最常用的架构模式,它把不同的程序功能物理的分配给各个硬件来执行。这样,如果我们想提高应用程序的性能的话,加一些硬件就可以达到目的了。按理说这种方法能提高应用程序的性能,但是我们应该避免使用这种方法。所以,只要有可能,我们都应该把asp.net页面和它用到的组件放到一个应用程序中运行。
  因为分布式的布署,要用到web services或者Remoting,它将使应用程序的性能下降20%或者更多。
   对于数据层有点不同,最好还是把它独立出来布署,用一个单独的硬件来运行它。虽然这样,但是数据库仍然是应用程序性能的瓶颈。因此,当你想优化你的程序的时候,首先想到的地方就应该是优化数据层了。
  在修改应用程序的出现性能问题的地方之前,你要先确认出问题的地方的程序看起来很严密,性能分析器对于查找应用程序哪些地方花费了多长时间非常有用。这些地方是我们用直觉感觉不到的。
  本文讨论两种类型的性能优化:一种是大的性能优化(big optimizations),如用asp.net的Cache;另一种是小的性能优化(tiny optimizations)。小幅的性能优化有时候非常有用。你只对你的代码作一个小的改到,然后一次调用它一千或一万次。作一次大的性能优化,你会发生你的应用程序的速度会有一个很大的提升。作一次小的性能优化,也许每次请求只能提高一微秒,但是如果每天的请求量很大的话,那么应用程序就有很显著的性能提升。
  数据层的性能
当你要优化一个应用程序的性能的时候,你可以按下面的顺序工作:你的代码要访问数据库?如果要,访问数据库频率怎么样?同样,这种测试方法也可以用在用web services或Remoting的程序代码中。本文将不讨论用Web services和Remoting的程序优化的问题。
  如果在你的代码中有一段必须访问数据库的请求,而你在其它的地方又看到实现同样的功能 的代码,那么你首先要优化它。修改和完善继续测试,除非你有一个非常大的性能问题,你的时间最好花在优化查询,连接数据库,返回数据集的大小,以及一次查询往返回的时间上。
  根据经验的总结,让我们来看看十个能帮助你提升你的应用程序性能的经验,我将按将它们提升效率的多少从大到小小依次说明。

一、返回多个数据集
   检查你的访问数据库的代码,看是否存在着要返回多次的请求。每次往返降低了你的应用程序的每秒能够响应请求的次数。通过在单个数据库请求中返回多个结果集,可以减少与数据库通信的时间,使你的系统具有扩展性,也可以减少数据库服务器响应请求的工作量。
  如果你是用动态的SQL语句来返回多个数据集,那我建议你用存储过程来替代动态的SQL语句。是否把业务逻辑写到存储过程中,这个有点争议。但是我认为,把业务逻辑写到存储过程里面可以限制返回结果集的大小,减小网络数据的流量,在逻辑层也不用在过滤数据,这是一个好事情。
  用SqlCommand对象的ExecuteReader方法返回一个强类型的业务对象,再调用NextResult方法来移动数据集指针来定位数据集。示例一演示了一个返回多个ArrayList强类型对象的例子。只从数据库中返回你需要的数据可以大大的减小你的服务器所耗用的内存。
  二、对数据进行分页
   ASP。NET的DataGrid有一个非常有用的功能:分页。如果DataGrid允许分页,在某一时刻它只下载某一页的数据,另外,它有一个数据分页的济览导航栏,它让你可以选择浏览某一页,而且每次只下载一页的数据。
  但是它有一个小小的缺点,就是你必须把所有的数据都绑定到DataGrid中。也就是说,你的数据层必须返回所有的数据,然后DataGrid再根据当前页过滤出当前页所需要的数据显示出来。如果有一个一万条记录的结果集要用DataGrid进行分页,假设DataGrid每页只显示25条数据,那就意味着每次请求都有9975条数据都是要丢弃的。每次请求都要返回这么大的数据集,对应用程序的性能影响是非常大的。
  一个好的解决方案是写一个分页的存储过程,例子2是一个用于对Northwind数据库orders表的分页存储过程。你只需要传当前页码,每页显示的条数两个参数进来,存储过程会返回相应的结果。
  在服务器端,我专门写了一个分页的控件来处理数据的分页,在这里,我用了第一个方法,在一个存储过程里面返回了两个结果集:数据记录总数和要求的结果集。
  返回的记录总数取决于要执行查询,例如,一个where条件可以限制返回的结果集的大小。因为在分页界面中必须要根据数据集记录的大小来计算总的页数,所以必须要返回结果集的记录数。例如,如果一共有1000000条记录,如果用where条件就可以过滤成只返回1000条记录,存储过程的分页逻辑应该知道返回那些需要显示的数据。
  三、连接池
   用TCP来连接你的应用程序与数据库是一件昂贵的事情(很费时的事情),微软的开发者可以通过用连接池来反复的使用数据库的连接。比起每次请求都用TCP来连一次数据库,连接池只有在不存在有效的连接时才新建一个TCP连接。当关闭一个连接的时候,它会被放到池中,它仍然会保持与数据库的连接,这样就可以减少与数据库的TCP连接次数。
  当然,你要注意那些忘记关的连接,你应在每次用完连接后马上关闭它。我要强调的是:无论什么人说.net framework中的GC(垃圾收集器)总会在你用完连接对象后调用连接对象的Close或者Dispose方法显式的关闭你的连接。不要期望CLR会在你想象的时间内关掉连接,虽然CLR最终都要销毁对象和关闭边接,但是我们并不能确定它到底会在什么时候做这些事情。
  要用连接池优化,有两条规则,第一,打开连接,处理数据,然后关闭连接。如果你必须在每次请求中多次打开或关闭连接,这好过一直打开一个边接,然后把它传到各个方法中。第二,用相同的连接字符串(或者用相同的用户标识,当你用集成认证的时候)。如果你没有用相同的连接字符串,如你用基于登录用户的连接字符串,这将不能利用连接池的优化功能。如果你用的是集成的论证,因为用户很多,所以你也不能充分利用连接池的优化功能。.NET CLR提供了一个数据性能计数器,它在我们需要跟踪程序性能特性的时候非常有用,当然也包括连接池的跟踪了。
  无论你的应用程序什么时候要连在另一台机子的资源,如数据库,你都应该重点优化你连资源所花的时间,接收和发送数据的时间,以及往返回之间的次数。优化你的应用程序中的每一个处理点(process hop),它是提高你的应用的性能的出发点。
  应用程序层包含与数据层连接,传送数据到相应的类的实例以及业务处理的逻辑。例如,在Community Server中,要组装一个Forums或者Threads集合,然后应用业务逻辑,如授权,更重要的,这里要完成缓存逻辑。 
  四、 ASP。NET缓存API
  在写应用程序之前,你要做的第一件事是让应用程序最大化的利用ASP.NET的缓存功能。
  如果你的组件是要在Asp.net应用程序中运行,你只要把System.Web.dll引用到你的项目中就可以了。然后用HttpRuntime.Cache属性就可访问Cache了(也可以通过Page.Cache或HttpContext.Cache访问)。
  有以下几条缓存数据的规则。第一,数据可能会被频繁的被使用,这种数据可以缓存。第二,数据的访问频率非常高,或者一个数据的访问频率不高,但是它的生存周期很长,这样的数据最好也缓存起来。第三是一个常常被忽略的问题,有时候我们缓存了太多数据,通常在一台X86的机子上,如果你要缓存的数据超过800M的话,就会出现内存溢出的错误。所以说缓存是有限的。换名话说,你应该估计缓存集的大小,把缓存集的大小限制在10以内,否则它可能会出问题。在Asp.net中,如果缓存过大的话也会报内存溢出错误,特别是如果缓存大的DataSet对象的时候。
  这里有几个你必须了解的重要的缓存机制。首先是缓存实现了“最近使用”原则( a least-recently-used algorithm),当缓存少的时候,它会自动的强制清除那些无用的缓存。其次 “条件依赖”强制清除原则(expiration dependencies),条件可以是时间,关键字和文件。以时间作为条件是最常用的。在asp.net2.0中增加一更强的条件,就是数据库条件。当数据库中的数据发生变化时,就会强制清除缓存。要更深入的了解数据库条件依赖请看Dino Esposito 在MSDN杂志2004年七月刊的Cutting Edge专栏文章。Asp.net的缓存架构如下图所示:
  
  五、 预请求缓存
  在前面,我提到过即使我们只对某些地方作了一个小小的性能改进也可以获得大的性能提升,我非常喜欢用预请求缓存来提升程序的性能。
  虽然Cache API设计成用来保存某段时间的数据,而预请求缓存只是保存某个时期的某个请求的内容。如果某个请求的访问频率高,而且这个请求只需要提取,应用,修改或者更新数据一次。那么就可以预缓存该请求。我们举个例子来说明。
  在CS的论坛应用程序中,每一个页面的服务器控件都要求得到用于决定它的皮肤(skin)的自定义的数据,以决定用哪个样式表及其它的一些个性化的东西。这里面的某些数据可能要长时间的保存,有些时间则不然,如控件的skin数据,它只需要应用一次,而后就可以一直使用。
  要实现预请求缓存,用Asp.net 的HttpContext类,HttpContext类的实例在每一个请求中创建,在请求期间的任何地方都可以通过HttpContext.Current属性访问。HttpContext类有一个Items集合属性,在请求期间所有的对象和数据都被添加到这个集合中缓存起来。和你用Cache缓存访问频率高数据一样,你可以用HttpContext.Items缓存那些每个请求都要用到的基础数据。它背后的逻辑很简单:我们向HttpContext.Items中添加一个数据,然后再从它里面读出数据。  

提高ASP.Net应用程序性能的十大方法(二)

 

 

六、 后台处理
  通过上面的方法你的应用程序应该运行得很快了,是不是?但是在某些时候,程序中的一次请求中可能要执行一个非常耗时的任务。如发送邮件或者是检查提交的数据的正确性等。
  当我们把asp.net Forums 1.0集成在CS中的时侯,发现提交一个新的帖子的时候会非常的慢。每次新增一个帖子的时侯,应用程序首先要检查这个帖子是不是重复提的,然后用“badword”过滤器来过滤,检查图片附加码,作帖子的索引,把它添加到合适的队列中,验证它的附件,最后,发邮件到它的订阅者邮件箱中。显然,这个工作量很大。
  结果是它把大量的时间都花在做索引和发送邮件中了。做帖子的索引是一项很耗时的操作,而发邮件给订阅都需要连接到SMTP服务,然后给每一个订阅者都发一封邮件,随着订阅用户的增加,发送邮件的时间会更长。
  索引和发邮件并不需要在每次请求时触发,理想状态下,我们想要批量的处理这些操作,每次只发25封邮件或者每隔5分钟把所有的要发的新邮件发一次。我们决定使用与数据库原型缓存一样的代码,但是失败了,所以又不得不回到VS.NET 2005。
  我们在System.Threading命名空间下找到了Timer类,这个类非常有用,但却很少有人知道,Web开发人员则更少有人知道了。一旦他建了该类的实例,每隔一个指定的时间,Timer类就会从线程池中的一个线程中调用指定的回调函数。这意味着你的asp.net应用程序可以在没有请求的时候也可以运行。这就是后以处理的解决方案。你就可以让做索引和发邮件工作在后台运行,而不是在每次请求的时候必须执行。
  后台运行的技术有两个问题,第一是,当你的应用程序域卸载后,Timer类实例就会停止运行了。也就是不会调用回调方法了。另外,因为CLR的每个进程中都有许多的线程在运行,你将很难让Timer获得一个线程来执行它,或者能执行它,但会延时。Asp.net层要尽量少的使用这种技术,以减少进程中线程的数量,或者只让请求用一小部分的线程。当然如果你有大量的异步工作的话,那就只能用它了。
  这里没有足够的空间有贴代码,你可以从http://www.rob-howard.net/中下载示例程序,请下载Blackbelt TechEd 2004的示例程序。
  七、 页面输出缓存和代理服务
  Asp.net是你的界面层(或者说应该是),它包含页面,用户控件,服务器控件(HttpHandlers 和HttpModules)以及它们生成的内容。如果你有一个Asp.net页面用来输出html,xml,imgae或者是其它的数据,对每一个请求你都用代码来生成相同的输出内容,你就很有必要考虑用页面输出缓存了。
  你只要简单的把下面的这一行代码复制到你的页面中就可以实现了:
  <%@ PageOutputCache VaryByParams=”none” Duration=”60” %>
  你就可以有效的利用第一次请求里生成的页面输出缓存内容,60秒后重新生成一道页面内容。这种技术其实也是运用一些低层的Cache API来实现。用页面输出缓存有几个参数可以配置,如上面所说的VaryByParams参数,该参数表示什么时候触发重输出的条件,也可以指定在Http Get或Http Post 请求模式下缓存输出。例如当我们设置该参数为VaryByParams=”Report”的时候,default.aspx?Report=1或者default.aspx?Report=2请求的输出都会被缓存起来。参数的值可以是多个用分号隔开参数。
  许多人都没有意识到当用页面输出缓存的时候,asp.net也会生成HTTP头集(HTTP Header)保存在下游的缓存服务器中,这些信息可以用于Microsoft Internet安全性中以及加速服务器的响应速度。当HTTP缓存的头被重置时,请求的内容会被缓在网络资源中,当客户端再次请求该内容时,就不会再从源服务器上获得内容了,而直接从缓存中获得内容。
  虽然用页面输出缓存不提高你的应用程序性能,但是它能减少了从的服务器中加载已缓存页面内容的次数。当然,这仅限于缓存匿名用户可以访问的页面。因为一旦页面被缓存后,就不能再执行授权操作了。
  八、 用IIS6.0的Kernel Caching
  如果你的应用程序没用运行在IIS6.0(windows server 2003)中,那么你就失去了一些很好的提高应用程序性能的方法。在第七个方法中,我讲了用页面输出缓存提高应用程序的性能的方法。在IIS5.0中,当一个请求到来到IIS后,IIS会把它转给asp.net,当应用了页面输出缓存时,ASP.NET中的HttpHandler会接到该请求,HttpHandler从缓存中把内容取出来并返回。
  如果你用的是IIS6.0,它有一个非常好的功能就是Kernel Caching,而且你不必修改asp.net程序中任何代码。当asp.net接到一个已缓存的请求,IIS的Kernel Cache会从缓存中得到它的一份拷贝。当从网络中传来一个请求的时,Kernel层会得到该请求,如果该请求被缓存起来了,就直接把缓存的数据返回,这样就完工了。这就意味着当你用IIS的Kernel Caching来缓存页面输出时,你将获得不可置信的性能提升。在开发VS.NET 2005的 asp.net时有一点,我是专门负asp.net性能的程序经理,我的程序员用了这个方法,我看了所有日报表数据,发现用kernel model caching的结果总是最快的。它们的一个共同的特征就是网络的请求和响应量很大,但IIS只占用了5%的CPU资源。这是令人惊奇的。有许多让你使用用IIS6.0的理由,但kernel cashing是最好的一个。
  九、 用Gzip压缩数据
  除非你的CPU占用率太高了,才有必要用提升服务器性能的技巧。用gzip压缩数据的方法可以减少你发送到服务端的数据量,也可以提高页面的运行速度,同时也减少了网络的流量。怎么样更好的压缩数据取决于你要发送的数据,还有就是客户端的浏览器支不支持(IIS把用gzip压缩后的数据发送到客户端,客户端要支持gzip才能解析,IE6.0和Firefox都支持)。这样你的服务器每秒能多响应一些请求,同样,你也减少了发送响应的数据量,也就能多发送一些请求了。
  好消息,gzip压缩已经被集成在IIS6.0中了,它比IIS5.0中gzip更好。不幸的是,在IIS6.0中启用gzip压缩,你不能在IIS6.0的属性对话中设置。IIS开发团队把gzip压缩功能开发出来了,但他们却忘了在管理员窗口中让管理员能很方便的启用它。要启用gzip压缩,你只能深入IIS6.0的xml配置文件中修改它的配置。
  除了阅读本文以外,只好再看看Brad Wilson写的<<IIS6 压缩>>一文(http://www.dotnetdevs.com/articles/IIS6compression.aspx);另外还有一篇介绍aspx压缩基础知识的文章,Enable ASPX Compression in IIS。但是要注意,在IIS6中动态压缩和kernel cashing是互斥的。
  十、 服务器控件的ViewState
  ViewState是asp.net中的一个特性,它用于把生成页面要用的一状态值保存在一个隐藏域中。当页面被回传到服务器时,服务器要解析,校验和应用ViewState中的数据以还原页面的控件树。ViewState是一个非常有用的特性,它能持久化客户端的状态而不用cookie或者服务器的内存。大部分的服务器控件都是用ViewState来持久化那些在页面中与用户交互的元素的状态值。例如,用以保存用于分页的当前页的页码。
  用ViewState会带来一些负面的影响。首先,它加大的服务器的响应和请求的时间。其次,每次回传时都增加了序列化和反序列化数据的时间。最后,它还消耗了服务器更多的内存。
  许多的服务器控件很趋于使用ViewState,如众所周知的DataGrid,而有时候是没有必须使用的。默认情况下是允许使用ViewState的,如果你不想使用ViewState的话,你可以在控件或页面级别把关闭它。在控件中,你只要把EnableViewState属性设为False就可以了;你也可以在页面中设置,使它的范围扩展到整个页面中:
  <%@ Page EnableViewState=”false” %>
  如果页面无需回传或者每次请求页面只是呈现控件。你就应该在页面级别中把ViewState关掉。
  总结 
  我们只是提供几个认为有助于提高写高性能的asp.net应用程序的技巧,本文提到的提高asp.net性能的技巧只是一个起步,更多的信息请参考《Improving ASP.NET Performance》一书。只有通过自己的实践,你才能找到对你的项目最有帮助的技巧。然而,在你的开发旅程中,这些技巧可以起一些指导性的作用。在软件开发中,这些都不是绝对有用的,因为各个项目都不一样。 

Web.config详解+ASP.NET优化

一、认识Web.config文件
Web.config 文件是一个xml文本文件,它用来储存 asp.NET Web 应用程序的配置信息(如最常用的设置asp.NET Web 应用程序的身份验证方式),它可以出现在应用程序的每一个目录中。当你通过.NET新建一个Web应用程序后,默认情况下会在根目录自动创建一个默认的Web.config文件,包括默认的配置设置,所有的子目录都继承它的配置设置。如果你想修改子目录的配置设置,你可以在该子目录下新建一个Web.config文件。它可以提供除从父目录继承的配置信息以外的配置信息,也可以重写或修改父目录中定义的设置。
 (一).Web.Config是以xml文件规范存储,配置文件分为以下格式
1.配置节处理程序声明
特点:位于配置文件的顶部,包含在<configSections>标志中。
2.特定应用程序配置
特点: 位于<appSetting>中。可以定义应用程序的全局常量设置等信息.
3.配置节设置
特点: 位于<system.Web>节中,控制asp.net运行时的行为.
4.配置节组
特点: 用<sectionGroup>标记,可以自定义分组,可以放到<configSections>内部或其它<sectionGroup>标记的内部.
(二).配置节的每一节
1.<configuration>节根元素,其它节都是在它的内部.
2.<appSetting>节此节用于定义应用程序设置项。对一些不确定设置,还可以让用户根据自己实际情况自己设置
用法:
I.<appSettings>
<add key="Conntction" value="server=192.168.85.66;userid=sa;password=;database=Info;"/>
<appSettings>
定义了一个连接字符串常量,并且在实际应用时可以修改连接字符串,不用修改程式代码.
II.<appSettings>
<add key="ErrPage" value="Error.aspx"/><appSettings> 定义了一个错误重定向页面.
3.<compilation>节
格式:
<compilation
defaultLanguage="c#"
debug="true"
/>
I.default language: 定义后台代码语言,可以选择c#和vb.net两种语言.
IIdebug : 为true时,启动aspx调试;为false不启动aspx调试,因而可以提高应用程序运行时的性能。一般程序员在开发时设置为true,交给客户时设置为false.
4.<customErrors>节
格式:
<customErrors
mode="RemoteOnly"
defaultRedirect="error.aspx"
<error statusCode="440" redirect="err440page.aspx"/>
<error statusCode="500" redirect="err500Page.aspx"/>
/>
I.mode : 具有On,Off,RemoteOnly 3种状态。On表示始终显示自定义的信息; Off表示始终显示详细的asp.net错误信息; RemoteOnly表示只对不在本地Web服务器上运行的用户显示自定义信息.
II.defaultRedirect: 用于出现错误时重定向的URL地址. 是可选的
III.statusCode: 指明错误状态码,表明一种特定的出错状态.
IV. redirect:错误重定向的URL.
5.<globalization>节
格式:
<globalization
requestEncoding="utf-8"
responseEncoding="utf-8"
fileEncoding="utf-8"
/>
I.requestEncoding: 它用来检查每一个发来请求的编码.
II.responseEncoding: 用于检查发回的响应内容编码.
III.fileEncoding: 用于检查aspx,asax等文件解析的默认编码.
6.<sessionState>节
格式:
<sessionState
mode="InProc"
stateConnectionString="tcpip=127.0.0.1:42424"
sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes"
cookieless="false"
timeout="20"
/>
I.mode: 分为off,Inproc,StateServer,SqlServer几种状态
mode = InProc 存储在进程中特点:具有最佳的性能,速度最快,但不能跨多台服务器存储共享.mode = "StateServer" 存储在状态服务器中特点:   当需要跨服务器维护用户会话信息时,使用此方法。但是信息存储在状态服务器上,一旦状态服务器出现故障,信息将丢失. mode="SqlServer" 存储在sql server中特点:工作负载会变大,但信息不会丢失.
II. stateConnectionString :指定asp.net应用程序存储远程会话状态的服务器名,默认为本机
III.sqlConnectionString:当用会话状态数据库时,在这里设置连接字符串
IV. Cookieless:设置为true时,表示不使用cookie会话状态来标识客户;否则,相反.
V. TimeOut:用来定义会话状态存储的时间,超过期限,将自动终止会话.
7.<authentication>节
格式:
<authentication mode="Forms">
<forms name=".ASPXUSERDEMO" loginUrl="Login.aspx" protection="All" timeout="30"/>
</authentication>
<authorization>
<deny users="?"/>
</authorization>
I.Windows: 使用IIS验证方式
II.Forms: 使用基于窗体的验证方式
III.Passport: 采用Passport cookie验证模式
IV.None: 不采用任何验证方式
里面内嵌Forms节点的属性涵义:
I.Name: 指定完成身份验证的Http cookie的名称.
II.LoginUrl: 如果未通过验证或超时后重定向的页面URL,一般为登录页面,让用户重新登录
III.Protection: 指定 cookie数据的保护方式.
可设置为: All None Encryption Validation四种保护方式
a. All表示加密数据,并进行有效性验证两种方式
b. None表示不保护Cookie.
c. Encryption表示对Cookie内容进行加密
d. validation表示对Cookie内容进行有效性验证
IV. TimeOut: 指定Cookie的失效时间. 超时后要重新登录.
在运行时对Web.config文件的修改不需要重启服务就可以生效(注:<processModel> 节例外)。当然Web.config文件是可以扩展的。你可以自定义新配置参数并编写配置节处理程序以对它们进行处理。
web.config配置文件(默认的配置设置)以下所有的代码都应该位于
<configuration>
<system.web>

</system.web>
</configuration>
之间,出于学习的目的下面的示例都省略了这段xml标记。
1、<authentication> 节
作用:配置 asp.NET 身份验证支持(为Windows、Forms、PassPort、None四种)。该元素只能在计算机、站点或应用程序级别声明。< authentication> 元素必需与<authorization> 节配合使用。
示例:
以下示例为基于窗体(Forms)的身份验证配置站点,当没有登陆的用户访问需要身份验证的网页,网页自动跳转到登陆网页。
<authentication mode="Forms" >
<forms loginUrl="logon.aspx" name=".FormsAuthCookie"/>
</authentication>
其中元素loginUrl表示登陆网页的名称,name表示Cookie名称。
2、<authorization> 节
作用:控制对 URL 资源的客户端访问(如允许匿名用户访问)。此元素可以在任何级别(计算机、站点、应用程序、子目录或页)上声明。必需与<authentication> 节配合使用。
示例:以下示例禁止匿名用户的访问
<authorization>
   <deny users="?"/>
</authorization>
注:你可以使用user.identity.name来获取已经过验证的当前的用户名;可以使用web.Security.FormsAuthentication.RedirectFromLoginPage方法将已验证的用户重定向到用户刚才请求的页面.具体的
3、<compilation>节
作用:配置 asp.NET 使用的所有编译设置。默认的debug属性为“True”.在程序编译完成交付使用之后应将其设为False(Web.config文件中有详细说明,此处省略示例)
4、<customErrors>
作用:为 asp.NET 应用程序提供有关自定义错误信息的信息。它不适用于 xml Web services 中发生的错误。
示例:当发生错误时,将网页跳转到自定义的错误页面。
<customErrors defaultRedirect="ErrorPage.aspx" mode="RemoteOnly">
</customErrors>
其中元素defaultRedirect表示自定义的错误网页的名称。mode元素表示:对不在本地 Web 服务器上运行的用户显示自定义(友好的)信息。
5、<httpRuntime>节
作用:配置 asp.NET HTTP 运行库设置。该节可以在计算机、站点、应用程序和子目录级别声明。
示例:控制用户上传文件最大为4M,最长时间为60秒,最多请求数为100
<httpRuntime maxRequestLength="4096" executionTimeout="60" appRequestQueueLimit="100"/>
6、 <pages>
作用:标识特定于页的配置设置(如是否启用会话状态、视图状态,是否检测用户的输入等)。<pages>可以在计算机、站点、应用程序和子目录级别声明。
示例:不检测用户在浏览器输入的内容中是否存在潜在的危险数据(注:该项默认是检测,如果你使用了不检测,一要对用户的输入进行编码或验证),在从客户端回发页时将检查加密的视图状态,以验证视图状态是否已在客户端被篡改。(注:该项默认是不验证)
<pages buffer="true" enableViewStateMac="true" validateRequest="false"/>
7、<sessionState>
作用:为当前应用程序配置会话状态设置(如设置是否启用会话状态,会话状态保存位置)。
示例:
<sessionState mode="InProc" cookieless="true" timeout="20"/>
</sessionState>
注:
mode="InProc"表示:在本地储存会话状态(你也可以选择储存在远程服务器或SAL服务器中或不启用会话状态)
cookieless="true"表示:如果用户浏览器不支持Cookie时启用会话状态(默认为False)
timeout="20"表示:会话可以处于空闲状态的分钟数
8、<trace>
作用:配置 asp.NET 跟踪服务,主要用来程序测试判断哪里出错。
示例:以下为Web.config中的默认配置:
<trace enabled="false" requestLimit="10" pageOutput="false" traceMode="SortByTime" localOnly="true" />
注:
enabled="false"表示不启用跟踪;
requestLimit="10"表示指定在服务器上存储的跟踪请求的数目
pageOutput="false"表示只能通过跟踪实用工具访问跟踪输出;
traceMode="SortByTime"表示以处理跟踪的顺序来显示跟踪信息
localOnly="true" 表示跟踪查看器 (trace.axd) 只用于宿主 Web 服务器
自定义Web.config文件配置
自定义Web.config文件配置节过程分为两步。
1.在配置文件顶部 <configSections> 和 </configSections>标记之间声明配置节的名称和处理该节中配置数据的 .NET Framework 类的名称。
2.是在 <configSections> 区域之后为声明的节做实际的配置设置。
示例:创建一个节存储数据库连接字符串
<configuration>
  <configSections>
  <section name="appSettings" type="System.Configuration.NameValueFileSectionHandler, System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
</configSections>
  <appSettings>
   <add key="scon" value="server=a;database=northwind;uid=sa;pwd=123"/>
  </appSettings>
  <system.web>
   ......
  </system.web>
</configuration>
访问Web.config文件你可以通过使用ConfigurationSettings.AppSettings 静态字符串集合来访问 Web.config 文件示例:获取上面例子中建立的连接字符串。例如:
protected static string Isdebug = ConfigurationSettings.AppSettings["debug"]
二、web.config中的session配置详解
打开某个应用程序的配置文件Web.config后,我们会发现以下这段:
< sessionState
  mode="InProc"
  stateConnectionString="tcpip=127.0.0.1:42424"
  sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes"
  cookieless="false"
  timeout="20"
/>
  这一段就是配置应用程序是如何存储session信息的了。我们以下的各种操作主要是针对这一段配置展开。让我们先看看这一段配置中所包含的内容的意思。sessionState节点的语法是这样的:
< sessionState mode="Off|InProc|StateServer|SQLServer"
             cookieless="true|false"
             timeout="number of minutes"
             stateConnectionString="tcpip=serverStick out tongueort"
             sqlConnectionString="sql connection string"
             stateNetworkTimeout="number of seconds"
/>
必须有的属性是:属性选项描述
mode 设置将session信息存储到哪里
Ø         Off 设置为不使用session功能,
Ø         InProc 设置为将session存储在进程内,就是asp中的存储方式,这是默认值,
Ø         StateServer 设置为将session存储在独立的状态服务中,
Ø         SQLServer 设置将session存储在sql server中。
可选的属性是:属性选项描述
Ø         cookieless 设置客户端的session信息存储到哪里,
Ø         ture 使用Cookieless模式,
Ø         false 使用Cookie模式,这是默认值,
Ø         timeout 设置经过多少分钟后服务器自动放弃session信息,默认为20分钟。
stateConnectionString 设置将session信息存储在状态服务中时使用的服务器名称和端口号,例如:"tcpip=127.0.0.1:42424”。当mode的值是StateServer是,这个属性是必需的。
sqlConnectionString 设置与sql server连接时的连接字符串。例如"data source= localhost;Integrated Security=SSPI;Initial Catalog=northwind"。当mode的值是 SQLServer时,这个属性是必需的。
stateNetworkTimeout 设置当使用StateServer模式存储session状态时,经过多少秒空闲后,断开Web服务器与存储状态信息的服务器的tcp/IP连接的。默认值是10秒钟。
asp.NET中客户端session状态的存储
  在我们上面的session模型简介中,大家可以发现session状态应该存储在两个地方,分别是客户端和服务器端。客户端只负责保存相应网站的SessionID,而其他的session信息则保存在服务器端。在asp中,客户端的SessionID实际是以Cookie的形式存储的。如果用户在浏览器的设置中选择了禁用Cookie,那末他也就无法享受session的便利之处了,甚至造成不能访问某些网站。为了解决以上问题,在 asp.NET中客户端的session信息存储方式分为:Cookie和Cookieless两种。
  asp.NET中,默认状态下,在客户端还是使用Cookie存储session信息的。如果我们想在客户端使用Cookieless的方式存储session信息的方法如下:
  找到当前Web应用程序的根目录,打开Web.Config文件,找到如下段落:
< sessionState
  mode="InProc"
  stateConnectionString="tcpip=127.0.0.1:42424"
  sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes"
  cookieless="false"
  timeout="20"
/>
  这段话中的cookieless="false"改为:cookieless="true",这样,客户端的session信息就不再使用 Cookie存储了,而是将其通过URL存储。关闭当前的IE,打开一个新IE,重新访问刚才的Web应用程序,就会看到类似下面的样子:
其中,
http://localhost/MyTestApplication/(ulqsek45heu3ic2a5zgdl245) /default.aspx中黑体标出的就是客户端的session ID。注意,这段信息是由IIS自动加上的,不会影响以前正常的连接。
asp.NET中服务器端session状态的存储准备工作:
  为了您能更好的体验到实验现象,您可以建立一个叫做SessionState.aspx的页面,然后把以下这些代码添加到< body>< /body>中。
< scriptrunat="server">
Sub Session_Add(sender As Object, e As EventArgs)
  session("MySession") = text1.Value
  span1.InnerHtml = "Session data updated! < P>Your session contains: < font color=red>" & session("MySession"). ToString() & "< /font>"
End Sub
Sub CheckSession(sender As Object, eAs EventArgs)
  If (Session("MySession")Is Nothing) Then
    span1.InnerHtml = "NOTHING, session DATA LOST!"
  Else
    span1.InnerHtml = "Your session contains: < font color= red>" & session("MySession").ToString() & "<   /font>"
End If
End Sub
< /script>
< formrunat="server"id="Form2">
  < inputid="text1"type="text"runat="server"name="text1">
  < inputtype="submit"runat="server"OnServerClick="Session_Add"
      value="Add to session State " id="Submit1"name="Submit1">
  < inputtype="submit"runat="server"OnServerClick="CheckSession"
      value=" View session State " id="Submit2"name="Submit2">
< /form>
< hrsize="1">
< fontsize="6">< spanid="span1"runat="server" />< /font>
  这个SessionState.aspx的页面可以用来测试在当前的服务器上是否丢失了session信息。
将服务器session信息存储在进程中
  让我们来回到Web.config文件的刚才那段段落中:
< sessionState
  mode="InProc"
  stateConnectionString="tcpip=127.0.0.1:42424"
  sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes"
  cookieless="false"
  timeout="20"
/>
  当mode的值是InProc时,说明服务器正在使用这种模式。
  这种方式和以前asp中的模式一样,就是服务器将session信息存储在IIS进程中。当IIS关闭、重起后,这些信息都会丢失。但是这种模式也有自己最大好处,就是性能最高。应为所有的session信息都存储在了IIS的进程中,所以IIS能够很快的访问到这些信息,这种模式的性能比进程外存储session信息或是在sql server中存储session信息都要快上很多。这种模式也是asp.NET的默认方式。
  好了,现在让我们做个试验。打开刚才的SessionState.aspx页面,随便输入一些字符,使其存储在session中。然后,让我们让IIS重起。注意,并不是使当前的站点停止再开始,而是在IIS中本机的机器名的节点上点击鼠标右键,选择重新启动IIS。(想当初使用NT4时,重新启动IIS必须要重新启动计算机才行,微软真是@#$%^&)返回到SessionState.aspx页面中,检查刚才的session信息,发现信息已经丢失了。
将服务器session信息存储在进程外
  首先,让我们来打开管理工具->服务,找到名为:asp.NET State Service的服务,启动它。实际上,这个服务就是启动一个要保存session信息的进程。启动这个服务后,你可以从Windows任务管理器->进程中看到一个名为 aspnet_state.exe的进程,这个就是我们保存session信息的进程。
  然后,回到Web.config文件中上述的段落中,将mode的值改为StateServer。保存文件后的重新打开一个IE,打开 SessionState.aspx页面,保存一些信息到session中。这时,让我们重起IIS,再回到SessionState.aspx页面中查看刚才的session信息,发现没有丢失。
  实际上,这种将session信息存储在进程外的方式不光指可以将信息存储在本机的进程外,还可以将session信息存储在其他的服务器的进程中。这时,不光需要将mode的值改为StateServer,还需要在stateConnectionString中配置相应的参数。例如你的计算你是192.168.0.1,你想把session存储在ip为192.168.0.2的计算机的进程中,就需要设置成这样: stateConnectionString="tcpip=192.168.0.2:42424"。当然,不要忘记在192.168.0.2的计算机中装上.NET Framework,并且启动asp.NET State Services服务。
将服务器session信息存储在sql server中
  首先,还是让我们来做一些准备工作。启动sql server和sql server代理服务。在sql server中执行一个叫做 InstallSqlState.sql的脚本文件。这个脚本文件将在sql server中创建一个用来专门存储session信息的数据库,及一个维护session信息数据库的sql server代理作业。我们可以在以下路径中找到那个文件:
[system drive]\winnt\Microsoft.NET\Framework\[version]\
  然后打开查询分析器,连接到sql server服务器,打开刚才的那个文件并且执行。稍等片刻,数据库及作业就建立好了。这时,你可以打开企业管理器,看到新增了一个叫ASPState的数据库。但是这个数据库中只是些存储过程,没有用户表。实际上session信息是存储在了tempdb 数据库的ASPStateTempSessions表中的,另外一个ASPStateTempApplications表存储了asp中 application对象信息。这两个表也是刚才的那个脚本建立的。另外查看管理->SQL server代理->作业,发现也多了一个叫做ASPState_Job_DeleteExpiredSessions的作业,这个作业实际上就是每分钟去ASPStateTempSessions 表中删除过期的session信息的。
  接着,我们返回到Web.config文件,修改mode的值改为SQLServer。注意,还要同时修改sqlConnectionString的值,格式为:
sqlConnectionString="data source=localhost; Integrated Security=SSPI;"
  其中data source是指sql server服务器的ip地址,如果sql server与IIS是一台机子,写127.0.0.1 就行了。Integrated Security=SSPI的意思是使用Windows集成身份验证,这样,访问数据库将以asp.NET的身份进行,通过如此配置,能够获得比使用userid=sa;password=口令的sql server验证方式更好的安全性。当然,如果sql server运行于另一台计算机上,你可能会需要通过Active Directory域的方式来维护两边验证的一致性。
  同样,让我们做个试验。向SessionState.aspx中添加session信息,这时发现session信息已经存在 sql server中了,即使你重起计算机,刚才的session信息也不会丢失。现在,你已经完全看见了session信息到底是什么样子的了,而且又是存储在sql server中的,能干什么就看你的发挥了。
 
总结
三、asp.net 关于form认证的一般设置
asp.net 关于form认证的一般设置:
1: 在web.config中,加入form认证;
   <authentication mode="Forms">
            <forms name="auth" loginUrl="index.aspx" timeout="30"></forms>
</authentication>
<authorization>
        <deny users="?" />
 </authorization>
2: 如果有注册页面时还应该允许匿名用户调用注册页面进行注册;
以下代码应该在<configuration><system.web>之间,而不应该包含到<system.web>..</system.web>之间;
----------------表示允许匿名用户对 userReg.aspx页面进行访问.
 <location path="userReg.aspx">
 <system.web>
     <authorization>
         <allow users="?" />
     </authorization>
 </system.web>
</location>
3 在登录成功后要创建身份验证票, 表明已经通过认证的合法用户;
if(登陆成功)
System.Web.Security.FormsAuthentication.SetAuthCookie(用户名称, false);
  四、访问Web.config文件
  你可以通过使用ConfigurationSettings.AppSettings 静态字符串集合来访问 Web.config 文件示例:获取上面例子中建立的连接字符串。例如:
protected static string Isdebug = ConfigurationSettings.AppSettings["scon"]
asp.Net性能优化.
(一).选择会话状态存储方式
    在Webconfig文件配置:
    <sessionState mode="???" stateConnectionString="tcpip=127.0.0.1:42424"
         sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes"
      cookieless="false" timeout="20"/>
     
    asp.net有三种方式存储会话状态信息:
    1. 存储在进程中: 属性mode = InProc
       特点: 具有最佳的性能,速度最快,但不能跨多台服务器存储共享.
 
    2. 存储在状态服务器中: 属性mode = "StateServer"
       特点:   当需要跨服务器维护用户会话信息时,使用此方法。
               但是信息存储在状态服务器上,一旦状态服务器出现故障,信息将丢失
   
    3. 存储在sql server中: 属性mode="SqlServer"
       特点:   工作负载会变大,但信息不会丢失.
    补充一点:
       I. 由于某些页面不需要会话状态,则可以将会话状态禁用:
             代码如下: <%@ Page EnableSessionState="false" %>
       II.如果页面需要访问会话变量但不允许修改它们,可以设置页面会话状态为只读:
             代码如下: <%@ Page EnableSessionState="false" %>
    使用时可以根据具体情况选择某种方式
(二).使用Page.IsPostBack
    Page.IsPostBack表示是否是从客户端返回的. 初次运行时,不是从客户端返回,它的值
    为false,当触发页面上的事件或刷新页面时,Page.IsPostBack由于是回发的,值变为true;
    一般在: Page_Load方法中用:
    private void Page_Load(Object sender,EventArgs e)
    {
        if(!Page.IsPostBack)
        {
             ....; //初始化页面的代码。这些代码第一次页面初始化时执行,当第二次回发时,
                    //不会再执行。提高效率。
        }
    }
    往往很多时候不得不用IsPostBack, 因为有些控件初始化后,要保持它的状态.
    例如: DropDownList,如果每次都初始化,则用户无论选择其选项,都会被初始化为默认值.
(三).避免使用服务器控件
    1.一般的静态显示信息,尽量不要用服务端控件显示. 因为服务端控件需要回发服务端执行,
      会降低程序执行效率,一般用<DIV>显示即可.
      如果用了服务端控件,将: runat="server"去掉,也会提高效率.
    2.禁用服务端控件的状态视图,有些控件不需要维护其状态,可以设置其属性: EnableViewState=false;
      如果整个页面控件都不需要维持状态视图,则可以设置整个页面的状态视力为false:
         代码如下: <%@ Page EnableViewState="false"%>
    3.在Web.Config文件中配置:
          asp.NET Sessionss可以在Web.config或Machine.config中的Sessionsstate元素中配置。
          下面是在 Web.config中的设置的例子:
            <Sessionsstate timeout="10" cookieless="false" mode="Inproc" />
(四).避免使用DataGrid
    大家都知道DataGrid功能强大。但是功能强大的同时,增加了性能上的开销。一般用其它控件: DataList
    或Repeater控件能实现的,尽量不用DataGrid.
(五).字符串操作
    1.避免装箱操作. 装箱操作运行效率比较低.
      例如运行两个代码段:  
        string test="";
         for(for int i=0;i<10000;i++)
         {
             test = test + i;            
         }
         和
                  string test="";
         for(for int i=0;i<10000;i++)
         {
             test = test + i.ToString();            
         }
       下面的代码段显然效率要高.因为i是整型的,系统要先把i进行装箱转换为string型的,再进行连接. 需要时间
       读者可以Copy到自己机器上测试一下.
     2.使用StringBulider类
       在进行字符串连接时: string str = str1 + str2 + ....;
       一般超过三项连接,最好用StringBuilder来代替string类. StringBuilder可以避免重新创建string 对象造成
       的性能损失.
       一般用于组装sql语句时用到: StringBulider.
       读者可以到自己机器上测试一下.
3.尽量少用:
        try
        {}
        catch
        {}
        finally
        {}
        语句.此语句执行效率比较低.
(六).ADO.Net使用方面优化
     1.数据库连接打开和关闭。 在需要连接时打开,当访问完数据库要立刻关闭连接.
       举例说明,还是看两个代码段:
      I.
           DataSet ds = new DataSet();
           SqlConnection MyConnection = new SqlConnection("server=localhost; uid=sa; pwd=; database=NorthWind");
           SqlCommand myCommand = new SqlCommand(strSql,MyConnection);  
           SqlDataAdapter myAdapter=new SqlDataAdapter(queryStr,connectionStr);
        MyConnection.Open();      //打开连接
        for(int i=0;i<1000;i++)   //for循环模拟取得数据前的商业逻辑操作
         {
            Thread.Sleep(1000);
       }
       myAdapter.Fill(ds);
        for(int i=0;i<1000;i++)   //for循环模拟取得数据后的商业逻辑操作
        {
           Thread.Sleep(1000);
        }
        MyConnection.Close();     //关闭连接
        II.
           DataSet ds = new DataSet();
           SqlConnection MyConnection = new SqlConnection("server=localhost; uid=sa; pwd=; database=NorthWind");
           SqlCommand myCommand = new SqlCommand(strSql,MyConnection);  
           SqlDataAdapter myAdapter=new SqlDataAdapter(queryStr,connectionStr);       
         for(int i=0;i<1000;i++)   //for循环模拟取得数据前的商业逻辑操作
         {
            Thread.Sleep(1000);
       }
       MyConnection.Open();      //打开连接
           myAdapter.Fill(ds);
          MyConnection.Close();     //关闭连接
        for(int i=0;i<1000;i++)   ////for循环模拟取得数据后的商业逻辑操作
        {
           Thread.Sleep(1000);
        }
         显示II代码比I代码好的多,I中早早占着连接不放,如果用户很多的话,容易出现连接池满情况。严重时出现死机现象.
       2.数据库查询
          I. 直接生成sql语句。 sql server每次都要对其进行编译,在性能方面不会有很大的提高。另外也不够安全。容易被攻击.
          II. 使用带参数的sql命令。这种方式sql server只对其编译一次,对于不同的参数可以重复使用编译后的命令。提高了性能.
          III.使用sql server存储过程. 编译一次. 具有独立性,便于修改和维护. 一次能完成用语句发送多次的功能.减少了网络的
              流量。 并不一定存储过程一定比语句效率要高,如果商业逻辑很复杂的话,有时候用语句比存储过程效率要高.
(六).缓存优化
     缓存分为两种:页面缓存和API缓存.
    1.使用页面缓存和片段缓存
        <%@ OutputCache Duration="5" VaryByParam="None"%>
        <%@ OutputCache Duration=60 VaryByParam=”TextBox1,TextBox2” %>
      说明: Duration是设置Cache的过期时间;
          VarByParam是设置是否根据参数而变化,None时所有参数使用同一Cache,
          设置TextBox1时则根据TextBox1的不同值分别缓存;当有多个参数时则要组合缓存;
    2.API缓存。用于在应用程序中使用
       I. 一个Cache使用的例子:
          
http://blog.csdn.net/chengking/archive/2005/10/03/494545.aspx
       II.使用时注意Page.Cache和HttpContext.Current.Cache区别:
          它们指的同一个对象,在Page里,用Page.Cache,如果在global.asax或自己的类里用:HttpContext.Current.Cache 在有些事件中,由于其没有HttpContext,就用HttpRuntime.Cache.

如何最大限度提高.net的性能_asp.net技巧

 

1)避免使用ArrayList。
     因为任何对象添加到ArrayList都要封箱为System.Object类型,从ArrayList取出数据时,要拆箱回实际的类型。建议使用自定义的集合类型代替ArrayList。.net 2.0提供了一个新的类型,叫泛型,这是一个强类型,使用泛型集合就可以避免了封箱和拆箱的发生,提高了性能。

2)使用HashTale代替其他字典集合类型(如StringDictionary,NameValueCollection,HybridCollection),存放少量数据的时候可以使用HashTable.

3)为字符串容器声明常量,不要直接把字符封装在双引号" "里面。
      //避免
      //
      MyObject obj = new MyObject();
      obj.Status = "ACTIVE";

      //推荐
      const string C_STATUS = "ACTIVE";
      MyObject obj = new MyObject();
      obj.Status = C_STATUS;

4) 不要用UpperCase,Lowercase转换字符串进行比较,用String.Compare代替,它可以忽略大小写进行比较.
  
   例:
 
      const string C_VALUE = "COMPARE";
      if (String.Compare(sVariable, C_VALUE, true) == 0)
      {
      Console.Write("SAME");
      }


5) 用StringBuilder代替使用字符串连接符 “+”,.

      //避免
      String sXML = "<parent>";
      sXML += "<child>";
      sXML += "Data";
      sXML += "</child>";
      sXML += "</parent>";

      //推荐
      StringBuilder sbXML = new StringBuilder();
      sbXML.Append("<parent>");
      sbXML.Append("<child>");
      sbXML.Append("Data");
      sbXML.Append("</child>");
      sbXML.Append("</parent>");

6) If you are only reading from the XML object, avoid using XMLDocumentt, instead use XPathDocument, which is readonly and so improves performance.
如果只是从XML对象读取数据,用只读的XPathDocument代替XMLDocument,可以提高性能
      //避免
      XmlDocument xmld = new XmlDocument();
      xmld.LoadXml(sXML);
      txtName.Text = xmld.SelectSingleNode("/packet/child").InnerText;

.

      //推荐
      XPathDocument xmldContext = new XPathDocument(new StringReader(oContext.Value));
      XPathNavigator xnav = xmldContext.CreateNavigator();
      XPathNodeIterator xpNodeIter = xnav.Select("packet/child");
      iCount = xpNodeIter.Count;
      xpNodeIter = xnav.SelectDescendants(XPathNodeType.Element, false);
      while(xpNodeIter.MoveNext())
      {
      sCurrValues += xpNodeIter.Current.Value+"~";
      }


7) 避免在循环体里声明变量,应该在循环体外声明变量,在循环体里初始化。

      //避免
      for(int i=0; i<10; i++)
      {
      SomeClass objSC = new SomeClass();
      .
      .
      .

      }

      //推荐
      SomeClass objSC = null;
      for(int i=0; i<10; i++)
      {
      objSC = new SomeClass();
     
      .
      .
      .
      }

8) 捕获指定的异常,不要使用通用的System.Exception.

      //避免
      try
      {
      <some logic>
      }
      catch(Exception exc)
      {
      <Error handling>
      }
     
      //推荐
      try
      {
      <some logic>
      }
      catch(System.NullReferenceException exc)
      {
      <Error handling>
      }
      catch(System.ArgumentOutOfRangeException exc)
      {
      <Error handling>
      }
      catch(System.InvalidCastException exc)
      {
      <Error handling>
      }

9) 使用Try...catch...finally时, 要在finally里释放占用的资源如连接,文件流等
不然在Catch到错误后占用的资源不能释放。
       
        try
      {
         ...
      }
      catch
        {...}
        finally
        {
          conntion.close()
        }    
10) 避免使用递归调用和嵌套循环,使用他们会严重影响性能,在不得不用的时候才使用。

11) 使用适当的Caching策略来提高性能

如何对ASP.NET进行性能优化

一、SqlDataRead和Dataset的选择

  Sqldataread优点:读取数据非常快。如果对返回的数据不需做大量处理的情况下,建议使用SqlDataReader,其性能要比datset好很多。缺点:直到数据读完才可close掉于数据库的连接

  (SqlDataReader 读数据是快速向前的。SqlDataReader 类提供了一种读取从 SQL Server 数据库检索的只进数据流的方法。它使用 SQL Server 的本机网络数据传输格式从数据库连接直接读取数据。DataReader需及时显式的close。可及时的释放对数据的连接。)

  Dataset是把数据读出,缓存在内存中。缺点:对内存的占用较高。如果对返回的数据需做大量的处理用Dataset比较好些可以减少对数据库的连接操作。优点:只需连接一次就可close于数据库的连接

  *一般情况下,读取大量数据,对返回数据不做大量处理用SqlDataReader.对返回数据大量处理用datset比较合适.对SqlDataReader和Dataset的选择取决于程序功能的实现。

  二、ExecuteNonQuery和ExecuteScalar

  对数据的更新不需要返回结果集,建议使用ExecuteNonQuery。由于不返回结果集可省掉网络数据传输。它仅仅返回受影响的行数。如果只需更新数据用ExecuteNonQuery性能的开销比较小。

  ExecuteScalar它只返回结果集中第一行的第一列。使用 ExecuteScalar 方法从数据库中检索单个值(例如id号)。与使用 ExecuteReader 方法, 返回的数据执行生成单个值所需的操作相比,此操作需要的代码较少。

  *只需更新数据用ExecuteNonQuery.单个值的查询使用ExecuteScalar数据绑定的选择

  三、数据的绑定DataBinder

  一般的绑定方法<%# DataBinder.Eval(Container.DataItem, "字段名") %>用DataBinder.eval 绑定不必关心数据来源(Dataread或dataset)。不必关心数据的类型eval会把这个数据对象转换为一个字符串。在底层绑定做了很多工作,使用了反射性能。正因为使用方便了,但却影响了数据性能。来看下<%# DataBinder.Eval(Container.DataItem, "字段名") %>。当于dataset绑定时,DataItem其实式一个DataRowView(如果绑定的是一个数据读取器(dataread)它就是一个IdataRecord。)因此直接转换成DataRowView的话,将会给性能带来很大提升。

  <%# ctype(Container.DataItem,DataRowView).Row("字段名") %>

  *对数据的绑定建议使用<%# ctype(Container.DataItem,DataRowView).Row("字段名") %>。数据量大的时候可提高几百倍的速度。使用时注意2方面:1.需在页面添加<%@ Import namespace="System.Data"%>.2.注意字段名的大小写(要特别注意)。如果和查询的不一致,在某些情况下会导致比<%# DataBinder.Eval(Container.DataItem, "字段名") %>还要慢。如果想进一步提高速度,可采用<%# ctype(Container.DataItem,DataRowView).Row(0) %>的方法。不过其可读性不高。

  以上的是vb.net的写法。在c#中:<@% ((DataRowView)Container.DataItem)["字段名"] %>

  对查看页面每个执行过程状态最简单的办法:其页面的trace属性为true就可查看细节。

  一、使用存储过程:

  1、性能方面:存储过程提供了许多标准sql语言中所没有的高级特性。其传递参数和执行逻辑表达式的功能,有助于应用程序设计者处理复杂任务。另外,存储过程存储在本地服务器上,减少了执行该过程所需的网络传输宽带和执行时间。(存储过程已经对sql语句进行了预编译,所以其执行速度比在程序里执行sql语句快很多)

  2、程序结构方面:从程序的可扩展性看,使用存储过程会对程序以后的修改带来方便。比如数据库的结构改变了,只需修改相对应的存储结构,和程序中的调用部分即可。这部分不属于本文探讨范围,属于程序结构设计方面。所以不在此展开。

  3、程序安全性:使用存储过程可避免SQL Injection攻击。

  二、查询语句的优化(针对sql server2000)

  很多人只为目的写出sql语句,而不考虑sql语句的执行效率。在这我只提供一优化表顺序的方法,(sql语句的优化和原则将会在我的sql server2000学习笔记中专题讨论)

  对sql语句执行效率可用sql server2000的查询分析器来查看语句的执行过程。

  优化表顺序:一般情况下,sqlserver 会对表的连接作出自动优化。例如:select name,no from A join B on A. id=B.id join C on C.id=A.id where name=’wang’

  尽管A表在From中先列出,然后才是B,最后才是C。但sql server可能会首先使用c表。它的选择原则是相对于该查询限制为单行或少数几行,就可以减少在其他表中查找的总数据量。绝大多数情况下,sql server 会作出最优的选择,但如果你发觉某个复杂的联结查询速度比预计的要慢,就可以使用SET FORCEPLAN语句强制sql server按照表出现顺序使用表。如上例加上:SET FORCEPLAN ON…….SET FORCEPLAN OFF 表的执行顺序将会按照你所写的顺序执行。在查询分析器中查看2种执行效率,从而选择表的连接顺序。

  *使用SET FORCEPLAN选择表联结顺序

  三、页面的优化(.aspx)

  主要针对几个页面属性

  1、EnableViewState(页面的视图状态)。如果无特殊要求设置为false。使用ViewState ,每个对象都必须先序列化到 ViewState 中,然后再通过回传进行反序列化,因此使用 ViewState是没有代价的。尽量减少使用对象,如果可能,尽量减少放入 ViewState 中的对象的数目。下面情况基本上可以禁用viewstate:

  (1)页面控件 (.ascx)

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

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

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

  单个页面或每个页面都禁用 ViewState,如下所示:单个页面:<%@ Page EnableViewState="False" %> 每个页面:在 web.config 中 <Pages EnableViewState="false" /> EnableSessionState保持默认值即可(如果页面用到sessionstate它才会占用资源)。EnableViewStateMac如果无安全上的特殊要求,保持默认值。

  2、Pagelayout.页面布局模型。建议使用Flowlayout(元素不带绝对定位属性添加).Gridlayout(绝对定位属性)由于采用绝对定位,将会比Flowlayout生产更多的代码,主要是控件的定位信息。

  3、项目发布的时候切记解除页面的Debug状态。

  4、Html语言的优化。我的建议是熟练掌握Html/javascript,少用vs.net2003自动生产的代码,它会自动生成一些无用的html代码。

  5、smart navigation设置为true能让用户明显的感觉性能提高。启用此属性后对客户端和服务端影响不大.它能智能涮新需要涮新需涮新的部分.

  四、控件的选择:

  Html控件和服务器控件的选择。服务器控件带来的方便和功能上的实现是html控件所不能比拟的。但是是以牺牲服务器端的资源来取得的。我个人建议:如果html控件达不到所要实现的功能,而且和一些脚本语言(如javascrpt/vbscript)结合也不能实现的话。才会选择服务器控件。选择服务器控件后,也尽量对其控件优化,如取消一些页面状态等(具体看控件的优化)

  服务器控件的选择:主要针对几个常用数据控件说明一下:

  DataGrid:自带最强大的数据显示控件,内置了对数据的修改、删除、添加、分页等很多实用功能。如果你只需对数据显示的话,尽量不要选择DataGrid(它把数据都存储在viewstate中).也不要使用自带的分页功能,microsoft在自动分页的底层做了很多工作,虽然使用方便了,但性能开销大了。

  DataList:比DataGrid功能少了很多。但自定义性强了很多。特有的多行数据显示,给我们带来了很多方便。DataGrid能实现的功能,它基本能实现。所以建议使用它。

  Repeater:功能最少,但自定义性非常强。如果只需对数据显示,建议使用。由于减少了很多功能,对服务器的性能带来消耗最小。因此,如果是对数据显示的话,我基本上都是选择Repeater然后DataList最后DataGrid

  *尽量选择html控件。能在客户端实现的功能就在客户端实现(熟练掌握javascript),减少服务器的压力。数据控件选择顺序:Repeater、DataList、DataGrid

  五、服务器控件的优化:

  1、Viewstate

  控件的viewstate与页面的viewstate基本是一致的。用来保存控件的一些状态。处理原则和处理页面的viewstate一样。有兴趣的可以用Datagrid绑定数据测试下viewstate保存的数据量有多大,它所保存的数据基本和Datagrid显示的数据量大小是等同的。

  2、Ispostpack

  默认false.需要产生事件的时候才需设置为true.

  控件的优化,主要看你对此控件的熟悉情况。对控件内部运作的原理越了解,就会对其作出合适的优化。

  性能优化是三两句话说不清的,我所写出的仅仅是冰山一角,性能的优化是靠平时经验的积累和对程序的运作原理的不断认知。

在网上找到的就这些,感觉嘛,都差不多。都是一些基本的。其它的例如不用数据控件,直接输出到网页,SQL Server存储过程优化,网页设计优化等都没有说。

posted on 2010-07-06 14:39  HackerVirus  阅读(764)  评论(0编辑  收藏  举报