摘要:將相關數據緩存到客戶端的文本、Excel、Access文件與客戶端內存中,通過執行腳本程序啟動組件程序或其他程序,以實現客戶端緩存數據與Web頁面的交互,并將服務器端的相關處理程序遷移到客戶端,在客戶端建立“寫緩存”以解決ASP.NET程序運行緩慢的問題。這些策略可用于JSP與C/S模式到B/S模式遷移開發中。
關鍵詞:ASP.NET緩存;性能;頁面;緩存策略
0 引言
Visual Studio.NET是開發軟件的集成環境,它將Web程序與Windows程序的開發合二為一,開發效率高,Window程序的開發習慣幾乎都可以沿用,所以在業界的應用越來越普及。
但Visual Studio.NET開發出來的Web(ASP.NET)程序,執行時占用的內存空間和CPU等資源較多,運行速度令人難以接受。為解決這個問題,ASP.NET尤其第2版,提供了很多基于“緩存”策略的改進措施,歸納起來有:
(1)頁面輸出緩存。將整個頁面緩存到服務器的內存中,當有新請求時直接將其發送給客戶端,服務器不必再處理。
(2)頁面部分緩存。將頁面的靜態部分或相對不變部分緩存到服務器的內存中。
(3)數據緩存。將可能的待讀數據緩存到服務器端的內存或其他地方。這是數據庫管理系統(如SQL Server)的功能。
(4)利用存貯過程,提高數據庫管理系統的處理速度。
(5)通過程序及配置文件Web.Config設置應用程序級緩存策略。
這些方法均在服務器端實施,能在一定程度上提高Web程序的運行效率。我們在開發某B/S模式的系統時,盡管用盡了以上緩存方法,服務器仍然頻頻癱瘓,這迫使我們去研究其他緩存方法,以提高系統的運行效率。
1 基本思想
將緩存位置從服務器端轉移到客戶端,在客戶端利用各種方式建立緩存,減輕服務器的負擔,提高Web程序的運行速度。
“待讀”的數據可緩存于客戶機的硬盤、內存等處。當緩存到硬盤時,可保存在文本文件、Excel文件、數據庫文件(如DBF、MDB、DB)。當緩存到內存時,可保存到網頁的DOM(Document Object Model)對象,如HTML型的列表框、下拉列表框、隱藏型文本框中,也可保存到特殊對象,如TOM(Table Object Model)對象,即HTML型的表格控件中。
也可將寫回到服務器的數據緩存在客戶端,僅當提交數據時,才將寫緩存中的數據發送到服務器。
2 實施策略
為了在客戶端實現緩存,采用腳本語言編寫程序,完成對HTML型控件、文本文件、Excel工作簿、數據庫文件(Access的MDB文件、FoxPro的DBF文件等)等的操作。下面針對緩存位置的不同,分別介紹各種策略。
2.1策略一:將數據緩存到客戶端文本文件
本策略的基本思想是:用戶先從服務器下載該用戶相關的數據。并保存到客戶端的某個文本文件,然后斷開與服務器的連接。這樣,用戶的多數操作可在客戶端執行,只有當用戶提交數據時,才與庫服務器交互。其具體實施過程如圖1所示。

圖1 將數據緩存到客戶端文本文件
2.1.1轉換為文本文件并打包
為了盡快地將數據庫中的數據下載到客戶端,可采用“預處理”策略,根據用戶權限,先利用Windows程序從數據庫提取數據,將其轉換為文本文件,再壓縮打包并保存到ftp文件夾。
2.1.2下載文本文件的緩存包
(1)獲取壓縮包名:在用戶登錄網頁中調用報名網頁,在報名網頁的Page_Load事件中,根據登錄網頁中用戶輸入的相關信息,計算產生待下載壓縮包的URL值,利用Response.Write()語句,將其寫入到某表單的HTML控件中。核心語句為(C#語言):
string s0=\"
string s1=\"
\“></form>”;
string s11=String.Format(ss1,myUrl.ToString());
Response.Write(s0+s11);
(2)生成ftp命令清單abc.txt:為了采用非交互方式執行下載命令ftp,需建立下載命令清單文件,因此需利用腳本語言,為網頁onLoad事件編寫處理程序,使之在客戶端載入網頁時,建立此清單文件。核心語句(JavaScript語言)為:
var strMyFileName=\"D:\\abc.txt\":
var fileSysObj=new ActiveXObject(\"Scripting.FileSystemObject\");
var myFile=fileSysO bj.CreateTextFile(strMyFileName,true);
var rarFn=FormLove.hideUrl.value;
var ffpCmd=\"get\"+rarFn+\"D:\\\\\"+rarFn;
myFile.WriteLine(ftpCmd);
myFile.WriteLine(“quit”);myFile.close();
注意:需要將指定網站添加到“受信任的站點”。將命令清單abc.txt中的“get”命令,換成“put”或“mput”,可通過ftp命令,將客戶端的文件上傳到服務器。
(3)下載緩存包。調用ftp程序,執行abc.txt中的下載命令完成下載。核心語句為:
var shell=new ActiveXObject(\"Wscript.Shell\");
shell.run(\"%SystemRoot%\\system32\\ftp.exe-v-n-i-d-s:D:
\\\\abc.txt-A 192.168.1.2\"):
說明:如果擔心ftp服務器不安全,可以先用此方法,從某個公開的虛擬目錄下載一個專門下載文件的雙接口的組件程序,通過腳本程序啟動該組件程序,以完成緩存包的下載。
(4)解開緩存包。執行客戶端解包軟件RAR。核心語句為:
var rarCmd=\"D:\\WinRAR\\RAR.exe x D:\\\\\"+rarFn+\"D:\\\\\";
shell.run(rarCmd);
2.1.3對緩存在客戶端的數據進行操作
在網頁中添加HTML型控件,通過腳本程序打開客戶端的文本文件,從中讀取數據,某個操作完成后,也可將寫回到服務器的數據,緩存到客戶端的文本文件。這里,主要用到客戶端的FileSystemObject對象,其核心語句為:
myFile=fileSysObj.OpenTextFile(strMyFileName,8,true);
//8可追加,1為只讀
var rarFn=FormLove.hideUd.value;//獲取控件的值
s1=myFile.ReadLine():myFile.WriteLine(s2);
vat oOption=document.createElement(\"OPTION\");
//這是采用DOM模式操作控件
oOption.text=s1;oOption.value=i;Form2.yourDept.add(oOption);
Form2.yourName.value=rarFn;//注意:需要用HTML語句定義
runat?\"server\"的新Form
2.1.4提交數據
將緩存在客戶端文本文件中的數據,寫回到數據庫服務器的基本方法如下:
(1)從客戶端的文本文件依次讀取每行數據,分類(Update、Insert,Delete等)生成刷新服務端數據的SQL語句。注意:兩條SQL語句之間用“分號(;)”分隔。
(2)將這些SQL語句保存到隱藏型文本框中,如FormOk.myUpdate.value=strUpdate。
(3)通過新Form的Acdon參數,指明接收SQL語句的網頁文件,在該網頁的Page_Load()事件中,獲取隱藏型文本框中的SQL語句并執行之。核心語句為:
mycmdstr=Request.Form[\"myUpdate\"].ToStnng().Trim();
mycmd.CommandText=mycmdstr;
int nSuccess=mycmd.ExecuteNonQuery();
本策略僅在下載與提交數據時,客戶端才與服務器端發生交互,減輕了服務器的負擔。它適合于給HTML型控件填充選項數據,如下拉列表框、普通的列表框的選項數據等。
2.2策略二:將數據緩存到客戶端的Excel文件
對于結構化數據,在服務器端進行預處理時,要將待緩存的數據轉換為Excel文件格式,客戶端通過啟動Excel來讀/寫緩存數據。本策略實現過程與“策略一”類似,基本步驟如下:
(1)生成Excel文件,再壓縮打包并保存到ftp文件夾。
(2)下載Excel文件的壓縮包并解壓,方法與“策略一”相同。
(3)對客戶端的緩存數據進行操作。
啟動客戶端的Excel軟件,讀/寫緩存在Excel文件中數據,其核心語句為:
var myExcel=new ActiveXObject(\"Excel.Application\");
myExcel.Workbooks.Open(\"D:\\abcd.xls\");
var myWg=myExcel~Workbooks.Item(1);
var myWS=myWB.Worksheets(1);
var ss=myExcel.Workbooks.Count+\"\n\"
+myWB.Name+\"\n\"+myWS.Name+\"\\";
SS+=myVVS.Cells(1,1).Value+\"\n\";myWS.Cells(4,3).Value=20000;
說明:與HTML型控件的交互,與“策略一”相同。
(4)提交數據,與“策略一”類似,不同之處是啟動Excel去獲取工作簿中的數據。
2.3策略三:將數據緩存到客戶端的Access數據庫文件
服務器端的數據本來保存在數據庫,因此當在客戶端緩存時,將其保存到數據庫,如Access數據庫,應是明智的選擇。本策略的實現過程與“策略一”類似,基本步驟如下:
(1)生成MDB文件,然后壓縮打包并保存到ftp文件夾。
(2)下載MDB緩存壓縮包并解壓,實現方法與“策略一”相同。
(3)對緩存在客戶端的數據進行操作。
執行腳本程序,調用ADO組件程序,打開MDB文件,從中讀寫數據,其核心語句為:
var conn=new ActiveXObject(\"ADODB.connection\");
var strDb=\"D:\\Student.mdb\";
conn.ConnectionString=\"Data Source=\"+strOb+\";
Jet OLEDB:Engine Type=5;
Provider='Microsoft.Jet.OLEDB.4.O':
User ID=Admin\"var rs=new ActiveXObject(\"ADODB.Recordset\");
conn.Open();rs.open(\"SELECT*FROM userlnfo\",conn,1,3);
var oOption=document.createElement(\"OPTION\"):
oOption.text=rS(\"userDept\").Value;
oOption.value=rs(\"usedD\").Value;
Form2.yourDept.add(oOption);
var sql=\"UPDATE userlnfo SET userName='楊其蕓'
WHERE userlD='yqy\"';
conn.Execute(sql);
與HTML型控件的交互,與“策略一”相同。
(4)提交數據,與“策略一”相似,不同之處是通過ADO組件去獲取數據庫中的數據。
2.4策略四:緩存在客戶端的內存中
本策略旨在保存客戶端要寫回到服務器的數據。一般情況下,客戶端寫回到服務器的數據,要少于從服務器下載的數據。要寫回到服務器的數據,當緩存到內存時,執行效率會更高。
寫回服務器的數據,也是某個數據庫表中的一條記錄,因此我們在網頁中添加一個HTML型的Table控件,然后利用腳本語言,編寫往Table控件中存取數據的程序。其基本過程如下:
(1)建立表結構:在runat?\"server\"的Form中,添加HTML型Table控件,切換到HTML狀態,使該表格僅留一行,并定義tbody型變量。主要的HTML代碼為:
<TABLE id=\"myTable2\"><TR><TD>用戶名
</TD>……<TD>院系</TD></TR>
<tbody id=\"myBody2\"></tbody>
</TABLE>
(2)在runat?\"server\"的Form中,添加一系列輸入數據的HTML控件,并添加HTML型的按鈕為該按鈕的單擊事件。該處理程序的主要語句為:
oRow=myBody2.insertRow():oCell=oRow.insertCell();
oCell innerText=Form2.yourName.value;
(3)提交數據:將緩存在HTML型Table控件中的數據取出,并寫出刷新服務器數據的SQL語句。其核心語句為:
for(i=0;i<myBody2.rOWS.1ength;i++){
oRow=myBody2.rows(i):
for(j=0;j<oRow.cells.1ength;j++){strDisp+=oRow.celIs(j).
innerText+\",”:} }
……;//生成刷新服務器數據的SQL語句
2.5策略五:服務器端主動向客戶端下載數據
在很多的情況下,不能在預處理階段準備數據,只能在程序運行時確定要緩存的數據,這時可采用服務器主動向客戶端推送數據的方式。其基本流程如下:
(1)服務器端在某個事件(如Page_Load事件、DataGfid控件的SelectedlndexChange事件)發生時,執行相應的處理程序,在此程序中利用Response.Write()語句,將服務器中的數據,寫到一系列的HTML語句。其核心語句(c#語言)為:
Data.DataRow myRow=this.myds.Tables[\"core\"].
Rows[CurrentRowlndex];
string ss0=\"<form id\\\"FormLOVe\\">\";
string ss1=\"<input type=\\\"hide\\\" id=\\\"hXH\\\"value=\\{0}\\\"/>\";
string ss11=String.Format(ss1,myRow[\"XH\"].ToString());
Response.Write(ss0):Response.Write(ss11);
(2)客戶端再在某個事件觸發時,執行相應的腳本程序,從這一系列的HTML語句中,獲取服務器端下發的數據。參考前述各策略所用方法,可將下發數據保存到文本文件、Excel文件、MDB文件、Table對象或其他位置。其核心語句有:
var oXH=FormLove.hXH.value;//獲取下發數據
Form2 txtXh.value oXH;
//保存到HTML型控件,也可保存到其他位置
(3)對緩存在客戶端的數據進行操作。方法見前述各策略。
(4)提交數據。實現方法見前述各策略,如“策略IN”。
以上過程,實現了服務器端控件與客戶端控件的雙向交流,即服務器端控件可將數據傳遞給HTML型控件;通過表單中的Action選項,HTML型控件可將數據傳遞給服務器端控件。
2.6策略六:在客戶端實現服務器端的某些功能
當將服務器端的數據緩存到客戶端后,還可將相關的處理程序,遷移到客戶端執行,進一步減輕服務器負擔,大大增強B/S模式中客戶端的處理能力,因此在某種程度上具有網格和分布式程序設計的思想。其基本步驟如下:
(1)將相關處理功能轉換為可獨立執行的程序,最好編寫為具有雙接口(dual interface)的COM型組件程序,使之既可以在Windows環境中執行,也可以在Web環境中被腳本調用。
(2)將相應程序壓縮并保存到ftp文件夾。
(3)將可執行程序包下載到客戶端并解開。方法見“策略一”中的介紹。
(4)客戶端通過腳本程序調用這些程序。
①若是具有雙接口的COM型組件程序,使用啟動Excel時所使用的方法,即var myApp=new ActiveXObjec(\"myCommyApp\")。其中“myCom”表示組件程序myComexe,“myApp”表示其主類名,如在Delphi為TmyApp=classfftypedComObjectJmyApp)。
②若是普通的程序,如ftp.exe、rar.exe,則可參考如下語句去執行:
var shell=new ActiveXObject(\"Wscript.Shell\");
shell.runt(\"%SystemRoot%\\system32\\ftp.exe-V—n-i—d-s:D:
\\abc.txt-A 192.168.1.2\");
3 結束語
將服務器端的相關數據,緩存到客戶端的文本文件、Excel文件、Access文件與客戶端內存中,在客戶端通過執行腳本程序,啟動組件程序或其他程序,讀寫這些緩存在客戶端的數據,減輕了服務器端的負擔。
同時將在服務器端執行的某些處理程序遷移到客觀端,可以分擔服務器的負載。
這些方法稍作修改可應用于JSP、ASP等Web程序中;同樣,這些方法稍作整理與推廣,可用于C/S模式系統向B/S模式的移植開發中。
注:本文中所涉及到的圖表、注解、公式等內容請以PDF格式閱讀原文。