ASP.NET Cache的一些總結(jié)
1.1.1 摘要
最近我們的系統(tǒng)面臨著嚴(yán)峻性能瓶頸問(wèn)題,這是由于訪問(wèn)量增加,客戶端在同一時(shí)間請(qǐng)求增加,這迫使我們要從兩個(gè)方面解決這一問(wèn)題,增加硬件和提高系統(tǒng)的性能。
大家可以通過(guò)各種各樣的方法去優(yōu)化我們系統(tǒng),本篇博文將介紹通過(guò)Cache方法來(lái)優(yōu)化系統(tǒng)的性能,減輕系統(tǒng)的負(fù)擔(dān)。
本文目錄
- 不同位置的緩存
- ASP.NET中的緩存
- 輸出緩存
- 客戶端緩存
- Query String緩存
- 自定義緩存控件
- 片段緩存
- 數(shù)據(jù)緩存
- SqlDataSource緩存
- 緩存的依賴關(guān)系
1.1.2 正文
不同位置的緩存
在Web應(yīng)用程序中的使用緩存位置主要有:客戶端瀏覽器緩存、客戶端和服務(wù)器中以及服務(wù)器端,因此緩存可以分為以下幾類:
- 客戶端緩存(Client Caching)
- 代理緩存(Proxy Caching)
- 反向代理緩存(Reverse Proxy Caching)
- 服務(wù)器緩存(Web Server Caching)
ASP.NET中的緩存
ASP.NET中有兩種緩存類型:輸出緩存和數(shù)據(jù)緩存。
輸出緩存:這是最簡(jiǎn)單的緩存類型,它保存發(fā)送到客戶端的頁(yè)面副本,當(dāng)下一個(gè)客戶端發(fā)送相同的頁(yè)面請(qǐng)求時(shí),此頁(yè)面不會(huì)重新生成(在緩存有限期內(nèi)),而是從緩存中獲取該頁(yè)面;當(dāng)然由于緩存過(guò)期或被回收,這時(shí)頁(yè)面會(huì)重新生成。
數(shù)據(jù)緩存
除此之外,還有兩個(gè)特殊的緩存:片段緩存和數(shù)據(jù)源緩存。
片段緩存:這是一種特殊的輸出緩存,它不是緩存整個(gè)頁(yè)面,而是緩存部分頁(yè)面;由于緩存整個(gè)頁(yè)面通常并不可行,因?yàn)轫?yè)面的某些部分是針對(duì)用戶定制的(例如用戶登陸信息),但我們可以把應(yīng)用程序中共享的部分進(jìn)行緩存,這時(shí)我們可以考慮使用片段緩存和用戶控件緩存。
數(shù)據(jù)源緩存:是建立在數(shù)據(jù)源控件的緩存,它包括SqlDataSource、ObjectDataSource和XmlDataSource控件。數(shù)據(jù)源緩存使用數(shù)據(jù)緩存方式,不同的是我們不需要通過(guò)顯示方法處理緩存;我們只需設(shè)置相應(yīng)的屬性,然后數(shù)據(jù)源控件就能存儲(chǔ)和檢索數(shù)據(jù)。
輸出緩存
輸出緩存可以把最終呈現(xiàn)的頁(yè)面緩存起來(lái),當(dāng)客戶端再次請(qǐng)求同一頁(yè)面時(shí),控制對(duì)象不再重新創(chuàng)建,頁(yè)面的生命周期不再啟動(dòng),無(wú)需再次執(zhí)行代碼,通過(guò)在緩存中獲取緩存的頁(yè)面。
現(xiàn)在我們?cè)O(shè)計(jì)一個(gè)頁(yè)面,每當(dāng)用戶發(fā)送頁(yè)面請(qǐng)求時(shí),就獲取當(dāng)前代碼執(zhí)行的時(shí)間,然后顯示在頁(yè)面上。
圖1輸出緩存
這是再簡(jiǎn)單不過(guò)的例子,每當(dāng)用戶發(fā)送頁(yè)面請(qǐng)求都會(huì)更新頁(yè)面顯示的時(shí)間,這是由于每次請(qǐng)求都獲取了一個(gè)新的頁(yè)面,實(shí)際情況中,我們并不需要實(shí)時(shí)的響應(yīng)用戶每個(gè)頁(yè)面請(qǐng)求,我們可以通過(guò)輸出緩存把頁(yè)面緩存起來(lái)每當(dāng)用戶發(fā)送同一頁(yè)面請(qǐng)求時(shí),而且在緩存有效期間,可以通過(guò)輸出緩存把緩存的頁(yè)面返回給用戶。
我們要實(shí)現(xiàn)輸出緩存,只需在頁(yè)面中添加如下代碼:
<!-- Adds OutputCache directive --> <%@ OutputCache Duration="23" VaryByParam="None" %>它支持五個(gè)屬性,其中兩個(gè)屬性Duration和VaryByParam是必填的
|
Duration |
必需屬性。頁(yè)面應(yīng)該被緩存的時(shí)間,以秒為單位。必須是正整數(shù)。 |
|
Location |
指定應(yīng)該對(duì)輸出進(jìn)行緩存的位置。如果要指定該參數(shù),則必須是下列選項(xiàng)之一:Any、Client、Downstream、None、Server 或 ServerAndClient。 |
|
VaryByParam |
必需屬性。Request 中變量的名稱,這些變量名應(yīng)該產(chǎn)生單獨(dú)的緩存條目。"none" 表示沒(méi)有變動(dòng)。"*" 可用于為每個(gè)不同的變量數(shù)組創(chuàng)建新的緩存條目。變量之間用 ";" 進(jìn)行分隔。 |
|
VaryByHeader |
基于指定的標(biāo)頭中的變動(dòng)改變緩存條目。 |
|
VaryByCustom |
允許在 global.asax 中指定自定義變動(dòng)(例如,"Browser")。 |
表1輸出緩存屬性
這里我們把輸出緩存的有效期設(shè)置為23秒,也就是說(shuō),當(dāng)緩存超過(guò)有效期就會(huì)被回收;當(dāng)用戶再次請(qǐng)求該頁(yè)面時(shí),就要重新創(chuàng)建頁(yè)面。
客戶端緩存
另一種選擇是客戶端緩存,如果用戶在瀏覽器中點(diǎn)擊“后退”按鈕或在地址欄中重新輸入U(xiǎn)RL,那么在這種情況下,瀏覽器將從緩存獲取頁(yè)面;然而,如果用戶點(diǎn)擊“刷新”按鈕,那么瀏覽器中緩存將失效,瀏覽器發(fā)送頁(yè)面請(qǐng)求。
如果我們要使用客戶端緩存,只需指定OutputCache中的屬性Location=”Client”就OK了,具體代碼如下所示:
<!-- Sets client OutputCache --> <%@ OutputCache Duration="23" VaryByParam="None" Location="Client" %>
通過(guò)在OutputCache中添加Location屬性,我們實(shí)現(xiàn)了客戶端緩存,通過(guò)設(shè)置客戶端緩存我們能夠減少的客戶端請(qǐng)求,也許有人會(huì)問(wèn):“每個(gè)用戶第一次頁(yè)面請(qǐng)求都需要服務(wù)器來(lái)完成,這不能很好的減少服務(wù)的壓力”。的確是這樣,相對(duì)于服務(wù)器緩存,客戶端緩存并沒(méi)有減少代碼的執(zhí)行和數(shù)據(jù)庫(kù)的操作,但是當(dāng)我們把包含個(gè)性化數(shù)據(jù)的頁(yè)面緩存在服務(wù)器中,客戶端請(qǐng)求頁(yè)面時(shí),由于不同的用戶個(gè)性化數(shù)據(jù)不同,這將會(huì)導(dǎo)致請(qǐng)求出現(xiàn)錯(cuò)誤,所以我們可以使用片段緩存把公用的部分緩存起來(lái)或客戶端緩存把用戶信息緩存起來(lái)。
Query String緩存
在前面的例子中,我們把OutputCache中的VaryByParam屬性設(shè)置為None,那么ASP.NET程序只緩存一個(gè)頁(yè)面副本;如果頁(yè)面請(qǐng)求包含查詢參數(shù),那么在緩存的有效期內(nèi),我們只可以查看到只是緩存結(jié)果,假設(shè)我們有個(gè)報(bào)表程序,它提供用戶根據(jù)產(chǎn)品名稱查詢相關(guān)的產(chǎn)品信息。
首先我們創(chuàng)建兩個(gè)頁(yè)面:查詢和結(jié)果頁(yè)面,由于時(shí)間關(guān)系我們已經(jīng)把頁(yè)面設(shè)計(jì)好了,具體如下所示:
圖2報(bào)表程序
首先我們提供查詢頁(yè)面,讓用戶根據(jù)成品名稱(ProductName)查詢相應(yīng)的成品信息,具體的代碼如下:
protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { // Gets product id from table Production.Product. // Then binding data to drop down list control. InitControl(GetProductId()); } } /// <summary> /// Handles the Click event of the btnSubmit control. /// Redirects to relative product information page. /// </summary> protected void btnSubmit_Click(object sender, EventArgs e) { Response.Redirect(string.Format("Product.aspx?productname={0}", ddlProductName.SelectedValue)); }
當(dāng)用戶點(diǎn)擊Submit按鈕后,跳轉(zhuǎn)到Product頁(yè)面并且在Url中傳遞查詢參數(shù)——產(chǎn)品名稱(ProducName)。
接下來(lái),我們繼續(xù)完成查詢頁(yè)面,由于在前一頁(yè)面中傳遞了查詢參數(shù)ProductName,那么我們將根據(jù)ProductName查詢數(shù)據(jù)庫(kù)獲取相應(yīng)的產(chǎn)品信息,具體代碼如下所示:
protected void Page_Load(object sender, EventArgs e) { // Get product name. string productName = Request.QueryString["productname"]; // Binding data to data grid view control. InitControl(this.GetData(productName)); } /// <summary> /// Inits the control. /// </summary> /// <param name="ds">The dataset.</param> private void InitControl(DataSet ds) { dgvProduct.DataSource = ds; dgvProduct.DataBind(); } /// <summary> /// Gets the data. /// </summary> /// <param name="productName">Name of the product.</param> /// <returns>Returns dataset</returns> private DataSet GetData(string productName) { // The query sql base on product name. string sql = string.Format( "SELECT Name, ProductNumber, SafetyStockLevel, ReorderPoint, StandardCost, DaysToManufacture " + "FROM Production.Product WHERE ProductNumber='{0}'", productName); // Get data from table Production.Product. using (var con = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLCONN"].ToString())) using (var com = new SqlCommand(sql, con)) { com.Connection.Open(); ////gdvData.DataSource = com.ExecuteReader(); ////gdvData.DataBind(); var ada = new SqlDataAdapter(com); var ds = new DataSet(); ada.Fill(ds); return ds; } }
前面示例,我們通過(guò)Request的屬性QueryString獲取ProductName的值,然后根據(jù)ProductName查詢數(shù)據(jù)庫(kù),最后把獲取數(shù)據(jù)綁定到Datagridview控件中(注:前面實(shí)例沒(méi)有考慮SQL Injection問(wèn)題)。

圖3查詢結(jié)果
現(xiàn)在我們?cè)陧?yè)面中添加輸出緩存,如下代碼:
<!-- Adds OutputCache directive --> <%@ OutputCache Duration="30" VaryByParam="None" %>
前面提到當(dāng)輸出緩存的屬性VaryByParam=”None”時(shí),ASP.NET程序在緩存有效期內(nèi)只緩存一個(gè)頁(yè)面副本;現(xiàn)在我們?cè)诰彺嬗行趦?nèi)(30s)再發(fā)送請(qǐng)求。
圖4查詢結(jié)果
通過(guò)上圖我們發(fā)現(xiàn),現(xiàn)在查詢參數(shù)ProductName=BK-M18B-40,但查詢結(jié)果依然是ProductName=BB-9108的數(shù)據(jù),這是由于ASP.NET程序在緩存有效期內(nèi)只緩存一個(gè)頁(yè)面副本。
通過(guò)上面的示例,我們發(fā)現(xiàn)只緩存一個(gè)頁(yè)面是不適用包含查詢參數(shù)的頁(yè)面輸出緩存;其實(shí)前面的示例我們只需稍稍改動(dòng)就能符合查詢參數(shù)的情況了,想必大家已經(jīng)知道了,只需把VaryByParam屬性設(shè)置為“*”就OK了。
圖5查詢結(jié)果
現(xiàn)在查詢可以獲取相應(yīng)的結(jié)果,如果查詢參數(shù)和前一個(gè)請(qǐng)求相同并且該頁(yè)面緩存有效,那么緩存將被重用,否則,創(chuàng)建一個(gè)新的頁(yè)面緩存。
由于ASP.NET給每個(gè)查詢參數(shù)都添加了輸出緩存,但我們要注意的是是否真的有必要緩存每個(gè)查詢參數(shù)都緩存一個(gè)頁(yè)面副本,假設(shè)查詢Url中增加一個(gè)參數(shù)參數(shù)ProductId,那么現(xiàn)在Url中就有兩個(gè)查詢參數(shù)了(ProductName和ProductId)。
前面我們把VaryByParam設(shè)置為“*”,所為ASP.NET程序?qū)roductName和ProductId都創(chuàng)建頁(yè)面緩存,如果我們只針對(duì)ProductName創(chuàng)建頁(yè)面緩存,這時(shí)我們可以修改VaryByParam,具體如下所示:
<!-- Sets VaryByParam property--> <%@ OutputCache Duration="30" VaryByParam="productname" %>
自定義緩存控件
前面我們介紹了通過(guò)查詢參數(shù)實(shí)現(xiàn)緩存一個(gè)或多個(gè)頁(yè)面,其實(shí)ASP.NET也允許我們自定義緩存方式來(lái)決定是否緩存頁(yè)或重用現(xiàn)有的,這時(shí)我們可以通過(guò)設(shè)置VaryByCustom屬性來(lái)實(shí)現(xiàn)。
假設(shè),現(xiàn)在我們要設(shè)計(jì)基于不同UserHostName的緩存,由于程序在執(zhí)行過(guò)程中,首先調(diào)用全局方法GetVaryByCustomString()來(lái)確定是否緩存頁(yè)面或重用現(xiàn)有的,所以我們可以通過(guò)重寫(xiě)GetVaryByCustomString()方法實(shí)現(xiàn)基于UserHostName的緩存,首先我們創(chuàng)建一個(gè)Global.asax文件然后重新全局方法GetVaryByCustomString()具體實(shí)現(xiàn)如下:
/// <summary> /// Gets vary cache based on custom string value. /// </summary> /// <param name="context">Http context.</param> /// <param name="custom">custom string</param> /// <returns></returns> public override string GetVaryByCustomString(HttpContext context, string custom) { if (string.Equals(custom, "UserHostName", StringComparison.OrdinalIgnoreCase)) { // Indicates that the cache should be vary on user host name. return Context.Request.UserHostName; } return base.GetVaryByCustomString(context, custom); }
前面我們重寫(xiě)了GetVaryByCustomString()方法,使得UserHostName值不同時(shí),獲取相應(yīng)的緩存值。
然后讓程序基于UserHostName創(chuàng)建緩存,所以我們要在頁(yè)面添加以下代碼:
<!-- set vary cache based on custom string value --> <%@ OutputCache Duration="30" VaryByParam="None" VaryByCustom="UserHostName" %>
我們通過(guò)自定義現(xiàn)在GetVaryByCustomString()方法,實(shí)現(xiàn)了Web程序根據(jù)UserHostName實(shí)施不同的緩存方式,其實(shí),我們還可以實(shí)現(xiàn)更多種類緩存方案,例如:基于用戶角色、時(shí)間和Url等等。
片段緩存
在某些情況下,我們不能緩存整個(gè)頁(yè)面,但我們?nèi)韵刖彺娌糠猪?yè)面從而減輕系統(tǒng)的負(fù)擔(dān);其實(shí),我們可以通過(guò)兩種方法實(shí)現(xiàn):片段緩存和數(shù)據(jù)緩存.
為了實(shí)現(xiàn)片段緩存,我們需要?jiǎng)?chuàng)建自定義控件緩存部分頁(yè)面,然后我們把OutputCache指令添加到自定義控件中,這樣整個(gè)頁(yè)面將不會(huì)被緩存,而自定義緩存控件除外。
前面我們介紹了輸出緩存的使用,只需在頁(yè)面中添加OutputCache指令,假設(shè)我們要在幾個(gè)頁(yè)面中添加輸出緩存這可能比較簡(jiǎn)單,但我們要在幾十個(gè)頁(yè)面中添加輸出緩存功能,而且前面介紹的例子中Duration屬性值都是直接Hard code到每個(gè)頁(yè)面中,如果我們需要修改Duration屬性值,那么就必須修改每個(gè)頁(yè)面了,ASP.NET還需要重新編譯這些頁(yè)面,這不利于我們的維護(hù),最重要的是增加了我們的工作量。
其實(shí),我們可以在web.config文件中定義一個(gè)outputCacheProfile(ProductCacheProfile),然后在頁(yè)面中添加CacheProfile屬性并且賦值為ProductCacheProfile,web.config文件設(shè)置如下:
<caching> <!-- Sets out put cache profile--> <outputCacheSettings> <outputCacheProfiles> <add name="ProductCacheProfile" duration="30"/> </outputCacheProfiles> </outputCacheSettings> </caching>
現(xiàn)在,我們?cè)陧?yè)面中添加CacheProfile屬性,并且設(shè)置為ProductCacheProfile,如下所示:
<!-- set CacheProfile property --> <%@ OutputCache CacheProfile="ProductCacheProfile" VaryByParam="None" %>
數(shù)據(jù)緩存
Cache對(duì)象是線程安全:這表示無(wú)需顯式實(shí)現(xiàn)鎖定或解鎖,在添刪Cache對(duì)象中的元素,然而,在Cache對(duì)象中元素必須是線程安全的。例如,我們創(chuàng)建一個(gè)實(shí)體Product,而且存在多個(gè)客戶端可能同時(shí)操作該對(duì)象的情況,這時(shí)我們必須為實(shí)體Product實(shí)現(xiàn)鎖定和解鎖操作(同步操作請(qǐng)參考《單例模式(Singleton)的6種實(shí)現(xiàn)》)。
Cache對(duì)象中的緩存項(xiàng)自動(dòng)移除:當(dāng)緩存過(guò)期,依賴項(xiàng)被修改或內(nèi)存不足緩存ASP.NET會(huì)自動(dòng)移除該緩存項(xiàng)。
緩存項(xiàng)支持依賴關(guān)系:我們可以給緩存項(xiàng)添加文件、數(shù)據(jù)庫(kù)表或其他資源類型的依賴關(guān)系。
SqlDataSource緩存
當(dāng)我們?cè)赟qlDataSource控件中啟用緩存,它緩存SelectCommand中的結(jié)果;如果SQL查詢語(yǔ)句中帶有參數(shù)時(shí),SqlDataSource控件會(huì)緩存每一個(gè)參數(shù)值對(duì)應(yīng)的結(jié)果。
這跟我們之前通過(guò)輸出緩存實(shí)現(xiàn)報(bào)表程序緩存查詢頁(yè)面效果一樣,所以我們將使用SqlDataSource緩存實(shí)現(xiàn)該效果。
假設(shè)我們要提供一個(gè)報(bào)表程序,讓用戶通過(guò)選擇產(chǎn)品名稱(ProductName),獲取相應(yīng)的產(chǎn)品信息。
首先,我們?cè)陧?yè)面中創(chuàng)建兩個(gè)數(shù)據(jù)源控件:sourceProductName和sourceProduct,接著把數(shù)據(jù)源分別綁定到Dropdownlist和Gridview中,具體實(shí)現(xiàn)如下:
<!-- The product number datasource START --> <asp:SqlDataSource ID="sourceProductName" runat="server" ProviderName="System.Data.SqlClient" EnableCaching="True" CacheDuration="3600" ConnectionString="<%$ ConnectionStrings:SQLCONN %>" SelectCommand="SELECT ProductNumber FROM Production.Product"></asp:SqlDataSource> <!-- The product number datasource END --> <!-- The product datasource START --> <asp:SqlDataSource ID="sourceProduct" runat="server" ProviderName="System.Data.SqlClient" EnableCaching="True" CacheDuration="3600" ConnectionString="<%$ ConnectionStrings:SQLCONN %>" SelectCommand="SELECT Name, ProductNumber, SafetyStockLevel, ReorderPoint, StandardCost, DaysToManufacture FROM Production.Product WHERE ProductNumber=@ProductNumber"> <SelectParameters> <asp:ControlParameter ControlID="ddlProductNumber" Name="ProductNumber" PropertyName="SelectedValue" /> </SelectParameters> </asp:SqlDataSource> <!-- The product number datasource END --> <!-- Binding the product number to gridview control --> <!-- NOTE: Due to search and result in the same page, so need to set AutoPostBack is True--> <asp:DropDownList ID="ddlProductNumber" AutoPostBack="True" DataSourceID="sourceProductName" DataTextField="ProductNumber" runat="server"> </asp:DropDownList> <!-- Binding the product datasource to gridview control --> <asp:GridView ID="gvProduct" runat="server" DataSourceID="sourceProduct" CssClass="Product"> </asp:GridView>
現(xiàn)在我們對(duì)報(bào)表程序進(jìn)行查詢,如果ProudctName之前沒(méi)有被緩存起來(lái)就會(huì)創(chuàng)建相應(yīng)的緩存,而已經(jīng)緩存起來(lái)的將被重用,查詢結(jié)果如下:
緩存的依賴關(guān)系
緩存項(xiàng)之間的依賴
ASP.NET Cache允許我們建立緩存之間的依賴關(guān)系,即一個(gè)緩存項(xiàng)依賴于另一個(gè)緩存項(xiàng);以下示例代碼創(chuàng)建了二個(gè)緩存項(xiàng),并且它們之間建立依賴關(guān)系。具體實(shí)現(xiàn)如下:
// Creates cache object Key1. Cache["Key1"] = "Cache Item 1"; // Makes Cache["Key2"] dependent on Cache["Key1"]. string[] dependencyKey = new string[1]; dependencyKey[0] = "Key1"; // Creates a CacheDependency object. CacheDependency dependency = new CacheDependency(null, dependencyKey); // Establishs dependency between cache Key1 and Key2. Cache.Insert("Key2", "Cache Item 2", dependency);
現(xiàn)在,當(dāng)Key1緩存項(xiàng)更新或從緩存中刪除,Key2緩存項(xiàng)就會(huì)自動(dòng)從緩存刪除。
文件依賴
前面我們介紹了緩存項(xiàng)之間的依賴關(guān)系,ASP.NET Cache還提供緩存項(xiàng)與文件之間的依賴關(guān)系,當(dāng)文件被更新或刪除對(duì)應(yīng)的緩存項(xiàng)也將失效。
在上篇博文《Ajax與JSON的一些總結(jié)》的最后介紹的一個(gè)DEMO——Weibo Feed中,我們通過(guò)實(shí)時(shí)方式向新浪微博API發(fā)送請(qǐng)求獲取相應(yīng)的數(shù)據(jù),但在一定時(shí)間內(nèi)請(qǐng)求的次數(shù)是有限制的,一旦超出了限制次數(shù)就不再接受請(qǐng)求了(具體請(qǐng)參考Rate-limiting)。所以可以通過(guò)Cache的方式把數(shù)據(jù)緩存起來(lái),當(dāng)客戶端請(qǐng)求時(shí),如果緩存數(shù)據(jù)已經(jīng)存在那么直接返回?cái)?shù)據(jù),否則重新想微博API請(qǐng)求數(shù)據(jù)。
首先,我們創(chuàng)建一個(gè)HttpHandler,它負(fù)責(zé)向微博API發(fā)送請(qǐng)求并且把數(shù)據(jù)保存的文件中,最后把數(shù)據(jù)返回的客戶端。
圖7 請(qǐng)求流程
接下來(lái),我們定義CacheData()方法把微博數(shù)據(jù)保存到文本文件中并且建立緩存與數(shù)據(jù)文件的依賴關(guān)系。
/// <summary> /// Caches the data into text file. /// </summary> /// <param name="context">The http context</param> private void CacheData(HttpContext context) { // Weibo API. string uri = context.Request.QueryString["api"] + "?" + "source=" + context.Request.QueryString["source"] + "&" + "count=" + context.Request.QueryString["count"]; HttpWebResponse response = this.GetWeibos(uri); if (null == response) { throw new ArgumentNullException("Response is null"); } string jsonData; // Writes the reponse data into text file. using (var reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(response.CharacterSet))) { jsonData = reader.ReadToEnd(); } string dataPath = context.Server.MapPath("weibo.json"); using (var writer = new StreamWriter(dataPath, false, Encoding.GetEncoding(response.CharacterSet))) { writer.Write(jsonData); } // Establishs dependency between cache weibo and text file. // Sets cache expires after 2 minuntes. HttpRuntime.Cache.Insert("weibo", jsonData, Dep, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(2)); }
現(xiàn)在我們把數(shù)據(jù)保存到文本文件中并且建立了緩存weibo與數(shù)據(jù)文件的依賴關(guān)系,接下來(lái)我們要把JSON格式數(shù)據(jù)返回給客戶端。
/// <summary> /// Responses the weibo data. /// </summary> /// <param name="context">The http contex.</param> private void ResponseWeibo(HttpContext context) { // Gets the weibo cache data. byte[] buf = Encoding.UTF8.GetBytes(HttpRuntime.Cache["weibo"].ToString()); // Writes the data into output stream. context.Response.OutputStream.Write(buf, 0, buf.Length); context.Response.OutputStream.Flush(); ////context.Response.Close(); }
上面我們把JSON格式字符串轉(zhuǎn)換為Byte數(shù)值,然后寫(xiě)入到OutputStream中,最后把數(shù)據(jù)返回給客戶端。
// The function to get weibo data. loadWeibo: function() { $.ajax({ // Weibo API. url: "WeiboHandler.ashx", type: "GET", // NOTE: We get the data from same domain, // dataType is json. dataType: "json", data: { source: JQWeibo.appKey, count: JQWeibo.numWeibo }, // When the requet completed, then invokes success function. success: function(data, textStatus, xhr) { // Sets html structure. var html = '<div class="weibo">' + '<a target="_blank">USER</a>' + ':WEIBO_TEXT<div class="time">AGO</div>'; // Appends weibos into html page. for (var i = 0; i < data.length; i++) { $(JQWeibo.appendTo).append( html.replace('WEIBO_TEXT', JQWeibo.ify.clean(data[i].text)) // Uses regex and declare DOMAIN as global, if found replace all. .replace(/DOMAIN/g, data[i].user.domain) .replace(/USER/g, data[i].user.screen_name) .replace('AGO', JQWeibo.timeAgo(data[i].created_at)) ); } } }) }
1.1.3 總結(jié)
緩存可以使應(yīng)用程序的性能得到很大的提高,因此在設(shè)計(jì)應(yīng)用程序應(yīng)該予以考慮,本博文主要介紹了ASP.NET中輸出緩存和數(shù)據(jù)緩存的應(yīng)用場(chǎng)合和區(qū)別。
頁(yè)面緩存適用于生成的頁(yè)面通常都相同或改變時(shí)間比較固定情況,例如:數(shù)據(jù)在每小時(shí)都會(huì)更新,那么我們可以設(shè)置duration為3600s。
數(shù)據(jù)緩存適用生成的頁(yè)面總是在變化情況。
- http://www.codeproject.com/Articles/29899/Exploring-Caching-in-ASP-NET
- http://msdn.microsoft.com/zh-cn/library/aa478965.aspx#XSLTsection129121120120
- http://www.amazon.com/Beginning-ASP-NET-3-5-2008-Professional/dp/1590598911
|
|
關(guān)于作者:[作者]:
JK_Rush從事.NET開(kāi)發(fā)和熱衷于開(kāi)源高性能系統(tǒng)設(shè)計(jì),通過(guò)博文交流和分享經(jīng)驗(yàn),歡迎轉(zhuǎn)載,請(qǐng)保留原文地址,謝謝。 |

最近我們的系統(tǒng)面臨著嚴(yán)峻性能瓶頸問(wèn)題,這是由于訪問(wèn)量增加,客戶端在同一時(shí)間請(qǐng)求增加,這迫使我們要從兩個(gè)方面解決這一問(wèn)題,增加硬件和提高系統(tǒng)的性能。...









浙公網(wǎng)安備 33010602011771號(hào)