ASP.NET網站優化(轉自一位博友的文章,寫的很是好)

本文將介紹一些方法用於優化ASP.NET網站性能,這些方法都是不須要修改程序代碼的。 它們主要分爲二個方面: 1. 利用ASP.NET自身的擴展性進行優化。 2. 優化IIS設置。css

配置OutputCache

用緩存來優化網站性能的方法,估計是無人不知的。 ASP.NET提供了HttpRuntime.Cache對象來緩存數據,也提供了OutputCache指令來緩存整個頁面輸出。 雖然OutputCache指令使用起來更方便,也有很是好的效果, 不過,它須要咱們在那些頁面中添加這樣一個指令。html

對於設置過OutputCache的頁面來講,瀏覽器在收到這類頁面的響應後,會將頁面響應內容緩存起來。 只要在指定的緩存時間以內,且用戶沒有強制刷新的操做,那麼就根本不會再次請求服務端, 而對於來自其它的瀏覽器發起的請求,若是緩存頁已生成,那麼就能夠直接從緩存中響應請求,加快響應速度。 所以,OutputCache指令對於性能優化來講,是頗有意義的(除非全部頁面頁面都在頻繁更新)。java

在網站的優化階段,咱們能夠用Fiddler之類的工具找出一些內容幾乎不會改變的頁面,給它們設置OutputCache, 可是,按照傳統的開發流程,咱們須要針對每一個頁面文件執行如下操做: 1. 簽出頁面文件。 2. 添加OutputCache指令。 3. 從新發布頁面。 4. 簽入文件(若是遇到多分支並行,還可能須要合併操做)。 以上這些源代碼管理制度會讓一個簡單的事情複雜化,那麼,有沒一種更簡單的方法能解決這個問題呢?jquery

接下來,本文將介紹一種方法,它利用ASP.NET自身的擴展性,以配置文件的方式爲頁面設置OutputCache參數。 配置文件其它就是一個XML文件,內容以下:web

<?xml version="1.0" encoding="utf-8"?>
<OutputCache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                        xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Settings>
        <Setting Duration="3" FilePath="/Pages/a3.aspx"  />
        <Setting Duration="10" FilePath="/Pages/a5.aspx"  />
    </Settings>
</OutputCache>

看了這段配置,我想您應該也能猜到它能有什麼做用。瀏覽器

每一行配置參數爲一個頁面指定OutputCache所須要的參數, 示例文件爲了簡單隻使用二個參數,其它能夠支持的參數請參考OutputCache指令緩存

爲了能讓這個配置文件有效,須要在web.config中配置如下內容(適用於IIS7):性能優化

<system.webServer>
    <modules>
        <add name="SetOutputCacheModule" type="WebSiteOptimize.SetOutputCacheModule, WebSiteOptimize" />
    </modules>
</system.webServer>

在這裏,我註冊了一個HttpModule,它的所有代碼以下:服務器

public class SetOutputCacheModule : IHttpModule
{
    static SetOutputCacheModule()
    {
        // 加載配置文件
        string xmlFilePath = Path.Combine(HttpRuntime.AppDomainAppPath, "OutputCache.config");
        ConfigManager.LoadConfig(xmlFilePath);
    }

    public void Init(HttpApplication app)
    {
        app.PreRequestHandlerExecute += new EventHandler(app_PreRequestHandlerExecute);
    }

    void app_PreRequestHandlerExecute(object sender, EventArgs e)
    {
        HttpApplication app = (HttpApplication)sender;

        Dictionary<string, OutputCacheSetting> settings = ConfigManager.Settings;
        if( settings == null )
            throw new ConfigurationErrorsException("SetOutputCacheModule加載配置文件失敗。");

        // 實現方法:
        // 查找配置參數,若是找到匹配的請求,就設置OutputCache
        OutputCacheSetting setting = null;
        if( settings.TryGetValue(app.Request.FilePath, out setting) ) {
            setting.SetResponseCache(app.Context);
        }
    }

ConfigManager類用於讀取配置文件,並啓用了文件依賴技術,當配置文件更新後,程序會自動從新加載: 

internal static class ConfigManager
{
    private static readonly string CacheKey = Guid.NewGuid().ToString();

    private static Exception s_loadConfigException;
    private static Dictionary<string, OutputCacheSetting> s_settings;

    public static Dictionary<string, OutputCacheSetting> Settings
    {
        get{
            Exception exceptin = s_loadConfigException;
            if( exceptin != null )
                throw exceptin;

            return s_settings;
        }
    }

    public static void LoadConfig(string xmlFilePath)
    {
        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 = new System.Configuration.ConfigurationException(
                "初始化SetOutputCacheModule時發生異常,請檢查" + xmlFilePath + "文件是否配置正確。", ex);
        }


        if( dict != null ) {
            // 註冊緩存移除通知,以便在用戶修改了配置文件後自動從新加載。

            // 參考:細說 ASP.NET Cache 及其高級用法
            //          http://www.cnblogs.com/fish-li/archive/2011/12/27/2304063.html
            CacheDependency dep = new CacheDependency(xmlFilePath);
            HttpRuntime.Cache.Insert(CacheKey, xmlFilePath, dep,
                Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, CacheRemovedCallback);
        }

        s_settings = dict;
    }


    private static void CacheRemovedCallback(string key, object value, CacheItemRemovedReason reason)
    {
        string xmlFilePath = (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文件:

<link type="text/css" href="aaaa.css" rel="Stylesheet" />
<script type="text/javascript" src="bbb.js"></script>

在這種狀況下,若是使用了前面所說的【啓用內容過時】方法,那麼當有JS,CSS文件須要升級時, 因爲瀏覽器的緩存尚未過時,因此就不會請求服務器,此時會使用已緩存的版本, 所以可能會出現各類奇怪的BUG

對於前面談到的BUG,我認爲根源在於引用JS,CSS文件的方式有缺陷, 那種方法徹底沒有考慮到版本升級問題, 正確的方法有二種: 1. 給文件名添加版本號,像jquery那樣,每一個版本一個文件(jquery-1.4.4.min.js)。 2. 在URL後面添加一個版本號,讓原先的URL失效。

第一種方法因爲每次升級都產生了一個新文件,因此不存在緩存問題,可是,維護一大堆文件的成本可能會比較大, 所以我建議採用第二種方法來解決。

MyMVC的示例代碼中,我使用了下面的方法來引用這些資源文件:

<%= HtmlExtension.RefCssFileHtml("/css/StyleSheet.css")%>
<%= HtmlExtension.RefJsFileHtml("/js/MyPage/fish.js")%>

在頁面運行時,會產生以下的輸出結果:

<link type="text/css" rel="Stylesheet" href="/css/StyleSheet.css?_t=634642185820000000" />
<script type="text/javascript" src="/js/MyPage/fish.js?_t=634642154020000000"></script>

這二個工具方法的實現代碼以下(在MyMVC的示例代碼中): 

private static readonly string s_root = HttpRuntime.AppDomainAppPath.TrimEnd('\\');

public static string RefJsFileHtml(string path)
{
    string filePath = s_root + path.Replace("/", "\\");
    string version = File.GetLastWriteTimeUtc(filePath).Ticks.ToString();
    return string.Format("<script type=\"text/javascript\" src=\"{0}?_t={1}\"></script>\r\n", path, version);
}

public static string RefCssFileHtml(string path)
{
    string filePath = s_root + path.Replace("/", "\\");
    string version = File.GetLastWriteTimeUtc(filePath).Ticks.ToString();
    return string.Format("<link type=\"text/css\" rel=\"Stylesheet\" href=\"{0}?_t={1}\" />\r\n", path, version);
}

上面這種獲取文件版本號的方法,是一種比較簡單的解決方案。 每一個引用的地方在生成HTML代碼時,都會訪問文件的最後修改時間,這會給磁盤帶來一點讀的開銷, 若是您擔憂這種實現方式可能會給性能帶來影響,那麼也能夠增長一個配置文件的方式來解決(請自行實現), 例如如下結構:

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfFileVersion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <FileVersion FilePath="/js/JScript.js" Version="255324" />
    <FileVersion FilePath="/css/StyleSheet.css" Version="2324235" />
</ArrayOfFileVersion>

若是您認爲這種配置文件須要手工維護,不夠自動化,還能夠採用程序的方式自動在運行時維護一個列表, 總之,直接引用資源文件的方法是一種直接耦合,會給文件升級帶來麻煩, 咱們能夠經過一個外部方法來解開這個直接耦合(給FileVersion增長一個屬性還還能夠將內部地址改爲一個CDN地址)。

啓用壓縮

壓縮響應結果也是經常使用的網站優化方法,因爲如今的瀏覽器都已支持壓縮功能, 所以,若是在服務端能壓縮響應結果,對於網速較慢的用戶來講,會減小不少網絡傳輸時間,最終的體驗就是網頁顯示速度變快了!

IIS6雖然提供壓縮的設置界面,然而配置是基於服務器級別的:

注意:這裏的【應用程序文件】不包括aspx,若是須要壓縮aspx的響應, 須要手工修改x:\WINDOWS\system32\inetsrv\MetaBase.xml文件(參考加大字號部分): 

<IIsCompressionScheme    Location ="/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:

<httpModules>
    <remove name="Session"/>
    <remove name="RoleManager"/>
    <remove name="PassportAuthentication"/>
    <remove name="Profile"/>
    <remove name="ServiceModel"/>
</httpModules>

對於使用Forms身份認證的網站的來講,下面這些HttpModule也是能夠禁用的:

<httpModules>
    <remove name="WindowsAuthentication"/>
    <remove name="FileAuthorization"/>
</httpModules>

其它優化選項

優化ASP.NET網站是一個大的話題,除了博客中介紹的這些方法以外,還有如下方法也是能夠參考的: 1. 升級服務器硬件配置。 2. 使用Windows Server 2008以上版本操做系統(網絡性能比2003要好)。 3. 優化操做系統配置(例如禁用不須要的服務)。 4. 禁用調試模式。 5. 網站使用專用應用程序池。

相關文章
相關標籤/搜索