不修改代码优化 ASP.NET 网站性能的一些方法
本文将介绍一些方法用于优化ASP.NET网站性能,这些方法都是不需要修改程序代码的。它们主要分为二个方面:1. 利用ASP.NET自身的扩展性进行优化。2. 优化IIS设置。
配置OutputCache
用缓存来优化网站性能的方法,估计是无人不知的。 ASP.NET提供了HttpRuntime.Cache对象来缓存数据,也提供了OutputCache指令来缓存整个页面输出。虽然OutputCache指令使用起来更方便,也有非常好的效果,不过,它需要我们在那些页面中添加这样一个指令。
对于设置过OutputCache的页面来说,浏览器在收到这类页面的响应后,会将页面响应内容缓存起来。只要在指定的缓存时间之内,且用户没有强制刷新的操作,那么就根本不会再次请求服务端,而对于来自其它的浏览器发起的请求,如果缓存页已生成,那么就可以直接从缓存中响应请求,加快响应速度。因此,OutputCache指令对于性能优化来说,是很有意义的(除非所有页面页面都在频繁更新)。
在网站的优化阶段,我们可以用Fiddler之类的工具找出一些内容几乎不会改变的页面,给它们设置OutputCache,但是,按照传统的开发流程,我们需要针对每个页面文件执行以下操作:
1. 签出页面文件。
2. 添加OutputCache指令。
3. 重新发布页面。
4. 签入文件(如果遇到多分支并行,还可能需要合并操作)。
以上这些源代码管理制度会让一个简单的事情复杂化,那么,有没一种更简单的方法能解决这个问题呢?
接下来,本文将介绍一种方法,它利用ASP.NET自身的扩展性,以配置文件的方式为页面设置OutputCache参数。配置文件其它就是一个XML文件,内容如下:
| 1 2 3 4 5 6 7 8 | <?xmlversion="1.0"encoding="utf-8"?>    <Settings>        <SettingDuration="3"FilePath="/Pages/a3.aspx"/>        <SettingDuration="10"FilePath="/Pages/a5.aspx"/>    </Settings></OutputCache> | 
看了这段配置,我想您应该也能猜到它能有什么作用。
每一行配置参数为一个页面指定OutputCache所需要的参数,示例文件为了简单只使用二个参数,其它可以支持的参数请参考OutputCache指令。
为了能让这个配置文件有效,需要在web.config中配置以下内容(适用于IIS7):
| 1 2 3 4 5 | <system.webServer>    <modules>        <addname="SetOutputCacheModule"type="WebSiteOptimize.SetOutputCacheModule, WebSiteOptimize"/>    </modules></system.webServer> | 
在这里,我注册了一个HttpModule,它的全部代码如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | publicclassSetOutputCacheModule : IHttpModule{    staticSetOutputCacheModule()    {        // 加载配置文件        stringxmlFilePath = Path.Combine(HttpRuntime.AppDomainAppPath, "OutputCache.config");        ConfigManager.LoadConfig(xmlFilePath);    }    publicvoidInit(HttpApplication app)    {        app.PreRequestHandlerExecute += newEventHandler(app_PreRequestHandlerExecute);    }    voidapp_PreRequestHandlerExecute(objectsender, EventArgs e)    {        HttpApplication app = (HttpApplication)sender;        Dictionary<string, OutputCacheSetting> settings = ConfigManager.Settings;        if( settings == null)            thrownewConfigurationErrorsException("SetOutputCacheModule加载配置文件失败。");        // 实现方法:        // 查找配置参数,如果找到匹配的请求,就设置OutputCache        OutputCacheSetting setting = null;        if( settings.TryGetValue(app.Request.FilePath, outsetting) ) {            setting.SetResponseCache(app.Context);        }    } | 
ConfigManager类用于读取配置文件,并启用了文件依赖技术,当配置文件更新后,程序会自动重新加载:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | internalstaticclassConfigManager{    privatestaticreadonlystringCacheKey = Guid.NewGuid().ToString();    privatestaticException s_loadConfigException;    privatestaticDictionary<string, OutputCacheSetting> s_settings;    publicstaticDictionary<string, OutputCacheSetting> Settings    {        get{            Exception exceptin = s_loadConfigException;            if( exceptin != null)                throwexceptin;            returns_settings;        }    }    publicstaticvoidLoadConfig(stringxmlFilePath)    {        Dictionary<string, OutputCacheSetting> dict = null;        try{            OutputCacheConfig config = XmlHelper.XmlDeserializeFromFile<OutputCacheConfig>(xmlFilePath, Encoding.UTF8);            dict = config.Settings.ToDictionary(x => x.FilePath, StringComparer.OrdinalIgnoreCase);        }        catch( Exception ex ) {            s_loadConfigException = newSystem.Configuration.ConfigurationException(                "初始化SetOutputCacheModule时发生异常,请检查"+ xmlFilePath + "文件是否配置正确。", ex);        }        if( dict != null) {            // 注册缓存移除通知,以便在用户修改了配置文件后自动重新加载。            // 参考:细说 ASP.NET Cache 及其高级用法            CacheDependency dep = newCacheDependency(xmlFilePath);            HttpRuntime.Cache.Insert(CacheKey, xmlFilePath, dep,                Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, CacheRemovedCallback);        }        s_settings = dict;    }    privatestaticvoidCacheRemovedCallback(stringkey, objectvalue, CacheItemRemovedReason reason)    {        stringxmlFilePath = (string)value;        // 由于事件发生时,文件可能还没有完全关闭,所以只好让程序稍等。        System.Threading.Thread.Sleep(3000);        // 重新加载配置文件        LoadConfig(xmlFilePath);    }} | 
有了AutoSetOutputCacheModule,我们就可以直接使用配置文件为页面设置OutputCache参数,而不需要修改任何页面,是不是很容易使用?
说明:MyMVC框架已支持这种功能,所有相关的可以从MyMVC框架的源码中获取。
建议:对于一些很少改变的页面,缓存页是一种很有效的优化方法。
启用内容过期
每个网站都会有一些资源文件(图片,JS,CSS),这些文件相对于ASPX页面来说,它们的输出内容极有可能在一段长时间之内不会有变化,而IIS在响应这类资源文件时不会生成Cache-Control响应头。在这种情况下,浏览器或许会缓存它们,也许会再次发起请求(比如重启后),总之就是缓存行为不受控制且缓存时间不够长久。
有没有想过可以把它们在浏览器中长久缓存起来呢?
为了告诉浏览器将这些文件长久缓存起来,减少一些无意义的请求(提高页面呈现速度),我们可以在IIS中启用内容过期,这样设置后,IIS就能生成Cache-Control响应头,明确告诉浏览器将文件缓存多久。
在IIS6中,这个参数很好找到:
然而,在IIS7中,这个参数不容易被发现,需要以下操作才能找到:
选择网站(或者网站子目录)节点,双击【HTTP响应标头】
再点击右边的【设置常用标头】链接,
此时将会显示:
说明:【启用内容过期】这个设置可以基于整个网站,也可以针对子目录,或者一个具体的文件。
注意:如果您在IIS7中针对某个子目录或者文件设置【启用内容过期】,前面的对话框看起来是一模一样的,
然而,在IIS6中,我们可以清楚地从对话框的标题栏中知道我们在做什么:
有时真感觉IIS7的界面在退步!
最后我想说一句:可以直接为整个网站启用内容过期,ASPX页面是不会被缓存的!
说到这里可能有人会想:这个过期时间我该设置多久呢?
十分钟,2个小时,一天,还是一个月?
在我看来,这个时间越久越好。
可能有人又会说了:万一我要升级某个JS文件怎么办,时间设置久了,用户怎么更新呢?
如果你问我这个问题,我也只能说是你的代码不合理(毕竟你解决不了升级问题),想知道原因的话,请继续阅读。
解决资源文件升级问题
对于一些规模不大的网站来说,通常会将资源文件与程序文件一起部署到一个网站中。
这时可能会采用下面的方式来引用JS或者CSS文件:
| 1 2 | <linktype="text/css"href="aaaa.css"rel="Stylesheet"/><scripttype="text/javascript"src="bbb.js"></script> | 
在这种情况下,如果使用了前面所说的【启用内容过期】方法,那么当有JS,CSS文件需要升级时,由于浏览器的缓存还没有过期,所以就不会请求服务器,此时会使用已缓存的版本,因此可能会出现各种奇怪的BUG
对于前面谈到的BUG,我认为根源在于引用JS,CSS文件的方式有缺陷,那种方法完全没有考虑到版本升级问题,正确的方法有二种:
1. 给文件名添加版本号,像jquery那样,每个版本一个文件(jquery-1.4.4.min.js)。
2. 在URL后面添加一个版本号,让原先的URL失效。
第一种方法由于每次升级都产生了一个新文件,所以不存在缓存问题,但是,维护一大堆文件的成本可能会比较大,因此我建议采用第二种方法来解决。
在MyMVC的示例代码中,我使用了下面的方法来引用这些资源文件:
| 1 2 | <%= HtmlExtension.RefCssFileHtml("/css/StyleSheet.css")%><%= HtmlExtension.RefJsFileHtml("/js/MyPage/fish.js")%> | 
在页面运行时,会产生如下的输出结果:
| 1 2 | <linktype="text/css"rel="Stylesheet"href="/css/StyleSheet.css?_t=634642185820000000"/><scripttype="text/javascript"src="/js/MyPage/fish.js?_t=634642154020000000"></script> | 
这二个工具方法的实现代码如下(在MyMVC的示例代码中):
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | privatestaticreadonlystrings_root = HttpRuntime.AppDomainAppPath.TrimEnd('\\');publicstaticstringRefJsFileHtml(stringpath){    stringfilePath = s_root + path.Replace("/", "\\");    stringversion = File.GetLastWriteTimeUtc(filePath).Ticks.ToString();    returnstring.Format("<script type=\"text/javascript\" src=\"{0}?_t={1}\"></script>\r\n", path, version);}publicstaticstringRefCssFileHtml(stringpath){    stringfilePath = s_root + path.Replace("/", "\\");    stringversion = File.GetLastWriteTimeUtc(filePath).Ticks.ToString();    returnstring.Format("<link type=\"text/css\" rel=\"Stylesheet\" href=\"{0}?_t={1}\" />\r\n", path, version);} | 
上面这种获取文件版本号的方法,是一种比较简单的解决方案。每个引用的地方在生成HTML代码时,都会访问文件的最后修改时间,这会给磁盘带来一点读的开销,如果您担心这种实现方式可能会给性能带来影响,那么也可以增加一个配置文件的方式来解决(请自行实现),例如以下结构:
| 1 2 3 4 5 6 | <?xmlversion="1.0"encoding="utf-8"?>    <FileVersionFilePath="/js/JScript.js"Version="255324"/>    <FileVersionFilePath="/css/StyleSheet.css"Version="2324235"/></ArrayOfFileVersion> | 
如果您认为这种配置文件需要手工维护,不够自动化,还可以采用程序的方式自动在运行时维护一个列表,总之,直接引用资源文件的方法是一种直接耦合,会给文件升级带来麻烦,我们可以通过一个外部方法来解开这个直接耦合(给FileVersion增加一个属性还还可以将内部地址改成一个CDN地址)。
启用压缩
压缩响应结果也是常用的网站优化方法,由于现在的浏览器都已支持压缩功能,因此,如果在服务端能压缩响应结果,对于网速较慢的用户来说,会减少很多网络传输时间,最终的体验就是网页显示速度变快了!
IIS6虽然提供压缩的设置界面,然而配置是基于服务器级别的:
注意:这里的【应用程序文件】不包括aspx,如果需要压缩aspx的响应,需要手工修改x:\WINDOWS\system32\inetsrv\MetaBase.xml文件(参考加大字号部分):
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <IIsCompressionSchemeLocation="/LM/W3SVC/Filters/Compression/gzip"        HcCompressionDll="%windir%\system32\inetsrv\gzip.dll"        HcCreateFlags="1"        HcDoDynamicCompression="TRUE"        HcDoOnDemandCompression="TRUE"        HcDoStaticCompression="TRUE"        HcDynamicCompressionLevel="9"        HcFileExtensions="htm            html            txt            js            css            htc"        HcOnDemandCompLevel="10"        HcPriority="1"        HcScriptFileExtensions="asp            exe            aspx            axd"    > | 
说明:要修改MetaBase.xml,需要停止IIS Admin Service服务。
在IIS7中,我们可以在服务器级别配置压缩参数:
然后在每个网站中开启或者关闭压缩功能:
说明:IIS7中已经不再使用MetaBase.xml,所以我们找不到IIS6的那些设置了。 IIS7压缩的过滤条件不再针对扩展名,而是采用了mimeType规则(保存在applicationHost.config)。根据IIS7的压缩规则,当我们启用动态压缩后,会压缩aspx的响应结果。
二种压缩方法的差别:
1. 静态内容压缩:当服务器在第一次响应某个静态文件时,会生成一个压缩后的结果,并保存到磁盘中,以便重用。
2. 动态内容压缩:【每次】在响应客户端之前,压缩响应结果,在内存中完成,因此会给CPU带来一些负担。
注意:要不要【启用动态内容压缩】这个参数,需要评估服务器的CPU是否能以承受(观察任务管理器或者查看性能计数器)。
删除无用的HttpModule
对一个网站来说,ASP.NET提供的有些HttpMoudle可能并不是需要的,然而,如果你不去手工禁用它们,它们其实会一直运行。
比如 我会禁用下面这些HttpMoudle:
| 1 2 3 4 5 6 7 | <httpModules>    <removename="Session"/>    <removename="RoleManager"/>    <removename="PassportAuthentication"/>    <removename="Profile"/>    <removename="ServiceModel"/></httpModules> | 
对于使用Forms身份认证的网站的来说,下面这些HttpModule也是可以禁用的:
| 1 2 3 4 | <httpModules>    <removename="WindowsAuthentication"/>    <removename="FileAuthorization"/></httpModules> | 
其它优化选项
优化ASP.NET网站是一个大的话题,除了博客中介绍的这些方法之外,还有以下方法也是可以参考的:
1. 升级服务器硬件配置。
2. 使用Windows Server 2008以上版本操作系统(网络性能比2003要好)。
3. 优化操作系统配置(例如禁用不需要的服务)。
4. 禁用调试模式。
5. 网站使用专用应用程序池。
本文链接:http://www.cnblogs.com/oooweb/p/useful-development-skills.html
不修改代码优化 ASP.NET 网站性能的一些方法的更多相关文章
- 不修改代码就能优化ASP.NET网站性能的一些方法
		阅读目录 开始 配置OutputCache 启用内容过期 解决资源文件升级问题 启用压缩 删除无用的HttpModule 其它优化选项 本文将介绍一些方法用于优化ASP.NET网站性能,这些方法都是不 ... 
- 不修改代码就能优化ASP.NET网站性能的一些方法 [转]
		不修改代码就能优化ASP.NET网站性能的一些方法 阅读目录 开始 配置OutputCache 启用内容过期 解决资源文件升级问题 启用压缩 删除无用的HttpModule 其它优化选项 本文将介绍一 ... 
- ASP.NET网站性能优化
		如果你是一个做过ASP网站,又做过ASP.NET网站的程序员,你可能会发现,如果按正常的思路开发ASP.NET网站,ASP.NET网站的速度会比ASP网站慢很多,为什么强大的网站语言会比弱得慢的,原因 ... 
- asp.net网站性能优化2则
		摘要:Web服务器的性能优化有很多资料介绍了,多台主机负载均衡,查询结果的多级缓 存,数据库索引优化等都是常见的优化手段.随着后端优化空间越来越小,现在越来越多 的网站更注重前端性能的优化,就是浏览器 ... 
- 提高ASP.NET网站性能的方法
		http://www.360doc.com/content/14/0705/18/7662927_392224856.shtml Asp.NET有许多秘密,当你了解了这些秘密后,可以使得你的ASP ... 
- PHP提高网站性能的一些方法
		前段时间面试问到了这个问题,回答的不是很全面,就去问了度娘,得到了一些比较全的答案,由于出处较多就没法确定原文出处了.下面是分享的答案. 一.大型网站性能提高策略: 大型网站,比如门户网站,在面对大量 ... 
- Asp.Net_网站性能
		1.如果不想被微软包围(其实微软的一套并不贵,是被谣言传高了),数据层依然可以选择SQL Server数据库和存储过程. 2.缓存不再依赖.net自身提供的缓存机制,迁移到部署在Linux平台上的分布 ... 
- ASP.NET网站性能提升的几个方法
		1. HTTP 压缩 HTTP 压缩通常用于压缩从服务端返回的页面内容.它压缩HTTP请求和响应,这个会是巨大的性能提升.我的项目是基于Window Server 2003开发的,可以参考这篇文章. ... 
- 调试ASP.NET网站IIS环境问题解决方法汇总
		调试网站时出现错误,错误如下: 1. 分析器错误消息: 创建 RewriterConfig 的配置节处理程序时出错: 无法生成临时类(result=1).error CS2001: 未能找到源文件“C ... 
随机推荐
- eclipse建包的一些细节
			com.a :com.b 等会先在com文件夹下在 建立 a,b两个子文件夹,引用路径时 不可"*\\com.a\\*"而是"*\\com\\a\\*"这点基础 ... 
- UVALive - 6887 Book Club 有向环的路径覆盖
			题目链接: http://acm.hust.edu.cn/vjudge/problem/129727 D - Book Club Time Limit: 5000MS 题意 给你一个无自环的有向图,问 ... 
- HDU 5211 Mutiple 水题
			题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5211 题解: 1.筛法: #include<iostream> #include< ... 
- lintcode-401-排序矩阵中的从小到大第k个数
			401-排序矩阵中的从小到大第k个数 在一个排序矩阵中找从小到大的第 k 个整数. 排序矩阵的定义为:每一行递增,每一列也递增. 样例 给出 k = 4 和一个排序矩阵: [ [1 ,5 ,7], [ ... 
- [Oracle收费标准]
			http://www.oracle.com/us/corporate/pricing/technology-price-list-070617.pdf 1: 数据库 2. 中间件 3. weblogi ... 
- Android内存泄漏第二课--------(集合中对象没清理造成的内存泄漏 )
			一.我们通常把一些对象的引用加入到了集合容器(比如ArrayList)中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大.如果这个集合是static的话,那情况就更严重 ... 
- 【Python】python操作mysql
			pymysql模块对mysql进行 import pymysql # 创建连接 conn = pymysql.connect(host=, user='root', passwd='root', db ... 
- bzoj4569-萌萌哒
			题目 有一个长度为\(n\)的十进制数,用\(s\)表示.有\(m\)个限制条件,每个条件形如:\((l_1,r_1,l_2,r_2)\),表示\(s[l_1:r_1]=s[l_2:r_2]\). 现 ... 
- 转---秒杀多线程第八篇 经典线程同步 信号量Semaphore
			阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event& ... 
- NetBeans IDE驱动报错The path to the driver executable must be set by the web driver.chrome.driver.system property......
			问题:defaulstUserDataPath=C:\\Users\\user1\\AppData\\Local\\Google\\Chrome\\User Data\\Defaul 编译失败 解决 ... 
