摘要:將相關(guān)數(shù)據(jù)緩存到客戶端的文本、Excel、Access文件與客戶端內(nèi)存中,通過執(zhí)行腳本程序啟動組件程序或其他程序,以實(shí)現(xiàn)客戶端緩存數(shù)據(jù)與Web頁面的交互,并將服務(wù)器端的相關(guān)處理程序遷移到客戶端,在客戶端建立“寫緩存”以解決ASP.NET程序運(yùn)行緩慢的問題。這些策略可用于JSP與C/S模式到B/S模式遷移開發(fā)中。
關(guān)鍵詞:ASP.NET緩存;性能;頁面;緩存策略
0 引言
Visual Studio.NET是開發(fā)軟件的集成環(huán)境,它將Web程序與Windows程序的開發(fā)合二為一,開發(fā)效率高,Window程序的開發(fā)習(xí)慣幾乎都可以沿用,所以在業(yè)界的應(yīng)用越來越普及。
但Visual Studio.NET開發(fā)出來的Web(ASP.NET)程序,執(zhí)行時(shí)占用的內(nèi)存空間和CPU等資源較多,運(yùn)行速度令人難以接受。為解決這個(gè)問題,ASP.NET尤其第2版,提供了很多基于“緩存”策略的改進(jìn)措施,歸納起來有:
(1)頁面輸出緩存。將整個(gè)頁面緩存到服務(wù)器的內(nèi)存中,當(dāng)有新請求時(shí)直接將其發(fā)送給客戶端,服務(wù)器不必再處理。
(2)頁面部分緩存。將頁面的靜態(tài)部分或相對不變部分緩存到服務(wù)器的內(nèi)存中。
(3)數(shù)據(jù)緩存。將可能的待讀數(shù)據(jù)緩存到服務(wù)器端的內(nèi)存或其他地方。這是數(shù)據(jù)庫管理系統(tǒng)(如SQL Server)的功能。
(4)利用存貯過程,提高數(shù)據(jù)庫管理系統(tǒng)的處理速度。
(5)通過程序及配置文件Web.Config設(shè)置應(yīng)用程序級緩存策略。
這些方法均在服務(wù)器端實(shí)施,能在一定程度上提高Web程序的運(yùn)行效率。我們在開發(fā)某B/S模式的系統(tǒng)時(shí),盡管用盡了以上緩存方法,服務(wù)器仍然頻頻癱瘓,這迫使我們?nèi)パ芯科渌彺娣椒?,以提高系統(tǒng)的運(yùn)行效率。
1 基本思想
將緩存位置從服務(wù)器端轉(zhuǎn)移到客戶端,在客戶端利用各種方式建立緩存,減輕服務(wù)器的負(fù)擔(dān),提高Web程序的運(yùn)行速度。
“待讀”的數(shù)據(jù)可緩存于客戶機(jī)的硬盤、內(nèi)存等處。當(dāng)緩存到硬盤時(shí),可保存在文本文件、Excel文件、數(shù)據(jù)庫文件(如DBF、MDB、DB)。當(dāng)緩存到內(nèi)存時(shí),可保存到網(wǎng)頁的DOM(Document Object Model)對象,如HTML型的列表框、下拉列表框、隱藏型文本框中,也可保存到特殊對象,如TOM(Table Object Model)對象,即HTML型的表格控件中。
也可將寫回到服務(wù)器的數(shù)據(jù)緩存在客戶端,僅當(dāng)提交數(shù)據(jù)時(shí),才將寫緩存中的數(shù)據(jù)發(fā)送到服務(wù)器。
2 實(shí)施策略
為了在客戶端實(shí)現(xiàn)緩存,采用腳本語言編寫程序,完成對HTML型控件、文本文件、Excel工作簿、數(shù)據(jù)庫文件(Access的MDB文件、FoxPro的DBF文件等)等的操作。下面針對緩存位置的不同,分別介紹各種策略。
2.1策略一:將數(shù)據(jù)緩存到客戶端文本文件
本策略的基本思想是:用戶先從服務(wù)器下載該用戶相關(guān)的數(shù)據(jù)。并保存到客戶端的某個(gè)文本文件,然后斷開與服務(wù)器的連接。這樣,用戶的多數(shù)操作可在客戶端執(zhí)行,只有當(dāng)用戶提交數(shù)據(jù)時(shí),才與庫服務(wù)器交互。其具體實(shí)施過程如圖1所示。
圖1 將數(shù)據(jù)緩存到客戶端文本文件
2.1.1轉(zhuǎn)換為文本文件并打包
為了盡快地將數(shù)據(jù)庫中的數(shù)據(jù)下載到客戶端,可采用“預(yù)處理”策略,根據(jù)用戶權(quán)限,先利用Windows程序從數(shù)據(jù)庫提取數(shù)據(jù),將其轉(zhuǎn)換為文本文件,再壓縮打包并保存到ftp文件夾。
2.1.2下載文本文件的緩存包
(1)獲取壓縮包名:在用戶登錄網(wǎng)頁中調(diào)用報(bào)名網(wǎng)頁,在報(bào)名網(wǎng)頁的Page_Load事件中,根據(jù)登錄網(wǎng)頁中用戶輸入的相關(guān)信息,計(jì)算產(chǎn)生待下載壓縮包的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:為了采用非交互方式執(zhí)行下載命令ftp,需建立下載命令清單文件,因此需利用腳本語言,為網(wǎng)頁onLoad事件編寫處理程序,使之在客戶端載入網(wǎng)頁時(shí),建立此清單文件。核心語句(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();
注意:需要將指定網(wǎng)站添加到“受信任的站點(diǎn)”。將命令清單abc.txt中的“get”命令,換成“put”或“mput”,可通過ftp命令,將客戶端的文件上傳到服務(wù)器。
(3)下載緩存包。調(diào)用ftp程序,執(zhí)行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\"):
說明:如果擔(dān)心ftp服務(wù)器不安全,可以先用此方法,從某個(gè)公開的虛擬目錄下載一個(gè)專門下載文件的雙接口的組件程序,通過腳本程序啟動該組件程序,以完成緩存包的下載。
(4)解開緩存包。執(zhí)行客戶端解包軟件RAR。核心語句為:
var rarCmd=\"D:\\WinRAR\\RAR.exe x D:\\\\\"+rarFn+\"D:\\\\\";
shell.run(rarCmd);
2.1.3對緩存在客戶端的數(shù)據(jù)進(jìn)行操作
在網(wǎng)頁中添加HTML型控件,通過腳本程序打開客戶端的文本文件,從中讀取數(shù)據(jù),某個(gè)操作完成后,也可將寫回到服務(wù)器的數(shù)據(jù),緩存到客戶端的文本文件。這里,主要用到客戶端的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.a(chǎn)dd(oOption);
Form2.yourName.value=rarFn;//注意:需要用HTML語句定義
runat?\"server\"的新Form
2.1.4提交數(shù)據(jù)
將緩存在客戶端文本文件中的數(shù)據(jù),寫回到數(shù)據(jù)庫服務(wù)器的基本方法如下:
(1)從客戶端的文本文件依次讀取每行數(shù)據(jù),分類(Update、Insert,Delete等)生成刷新服務(wù)端數(shù)據(jù)的SQL語句。注意:兩條SQL語句之間用“分號(;)”分隔。
(2)將這些SQL語句保存到隱藏型文本框中,如FormOk.myUpdate.value=strUpdate。
(3)通過新Form的Acdon參數(shù),指明接收SQL語句的網(wǎng)頁文件,在該網(wǎng)頁的Page_Load()事件中,獲取隱藏型文本框中的SQL語句并執(zhí)行之。核心語句為:
mycmdstr=Request.Form[\"myUpdate\"].ToStnng().Trim();
mycmd.CommandText=mycmdstr;
int nSuccess=mycmd.ExecuteNonQuery();
本策略僅在下載與提交數(shù)據(jù)時(shí),客戶端才與服務(wù)器端發(fā)生交互,減輕了服務(wù)器的負(fù)擔(dān)。它適合于給HTML型控件填充選項(xiàng)數(shù)據(jù),如下拉列表框、普通的列表框的選項(xiàng)數(shù)據(jù)等。
2.2策略二:將數(shù)據(jù)緩存到客戶端的Excel文件
對于結(jié)構(gòu)化數(shù)據(jù),在服務(wù)器端進(jìn)行預(yù)處理時(shí),要將待緩存的數(shù)據(jù)轉(zhuǎn)換為Excel文件格式,客戶端通過啟動Excel來讀/寫緩存數(shù)據(jù)。本策略實(shí)現(xiàn)過程與“策略一”類似,基本步驟如下:
(1)生成Excel文件,再壓縮打包并保存到ftp文件夾。
(2)下載Excel文件的壓縮包并解壓,方法與“策略一”相同。
(3)對客戶端的緩存數(shù)據(jù)進(jìn)行操作。
啟動客戶端的Excel軟件,讀/寫緩存在Excel文件中數(shù)據(jù),其核心語句為:
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)提交數(shù)據(jù),與“策略一”類似,不同之處是啟動Excel去獲取工作簿中的數(shù)據(jù)。
2.3策略三:將數(shù)據(jù)緩存到客戶端的Access數(shù)據(jù)庫文件
服務(wù)器端的數(shù)據(jù)本來保存在數(shù)據(jù)庫,因此當(dāng)在客戶端緩存時(shí),將其保存到數(shù)據(jù)庫,如Access數(shù)據(jù)庫,應(yīng)是明智的選擇。本策略的實(shí)現(xiàn)過程與“策略一”類似,基本步驟如下:
(1)生成MDB文件,然后壓縮打包并保存到ftp文件夾。
(2)下載MDB緩存壓縮包并解壓,實(shí)現(xiàn)方法與“策略一”相同。
(3)對緩存在客戶端的數(shù)據(jù)進(jìn)行操作。
執(zhí)行腳本程序,調(diào)用ADO組件程序,打開MDB文件,從中讀寫數(shù)據(jù),其核心語句為:
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.a(chǎn)dd(oOption);
var sql=\"UPDATE userlnfo SET userName='楊其蕓'
WHERE userlD='yqy\"';
conn.Execute(sql);
與HTML型控件的交互,與“策略一”相同。
(4)提交數(shù)據(jù),與“策略一”相似,不同之處是通過ADO組件去獲取數(shù)據(jù)庫中的數(shù)據(jù)。
2.4策略四:緩存在客戶端的內(nèi)存中
本策略旨在保存客戶端要寫回到服務(wù)器的數(shù)據(jù)。一般情況下,客戶端寫回到服務(wù)器的數(shù)據(jù),要少于從服務(wù)器下載的數(shù)據(jù)。要寫回到服務(wù)器的數(shù)據(jù),當(dāng)緩存到內(nèi)存時(shí),執(zhí)行效率會更高。
寫回服務(wù)器的數(shù)據(jù),也是某個(gè)數(shù)據(jù)庫表中的一條記錄,因此我們在網(wǎng)頁中添加一個(gè)HTML型的Table控件,然后利用腳本語言,編寫往Table控件中存取數(shù)據(jù)的程序。其基本過程如下:
(1)建立表結(jié)構(gòu):在runat?\"server\"的Form中,添加HTML型Table控件,切換到HTML狀態(tài),使該表格僅留一行,并定義tbody型變量。主要的HTML代碼為:
<TABLE id=\"myTable2\"><TR><TD>用戶名
</TD>……<TD>院系</TD></TR>
<tbody id=\"myBody2\"></tbody>
</TABLE>
(2)在runat?\"server\"的Form中,添加一系列輸入數(shù)據(jù)的HTML控件,并添加HTML型的按鈕為該按鈕的單擊事件。該處理程序的主要語句為:
oRow=myBody2.insertRow():oCell=oRow.insertCell();
oCell innerText=Form2.yourName.value;
(3)提交數(shù)據(jù):將緩存在HTML型Table控件中的數(shù)據(jù)取出,并寫出刷新服務(wù)器數(shù)據(jù)的SQL語句。其核心語句為:
for(i=0;i<myBody2.rOWS.1ength;i++){
oRow=myBody2.rows(i):
for(j=0;j<o(jì)Row.cells.1ength;j++){strDisp+=oRow.celIs(j).
innerText+\",”:} }
……;//生成刷新服務(wù)器數(shù)據(jù)的SQL語句
2.5策略五:服務(wù)器端主動向客戶端下載數(shù)據(jù)
在很多的情況下,不能在預(yù)處理階段準(zhǔn)備數(shù)據(jù),只能在程序運(yùn)行時(shí)確定要緩存的數(shù)據(jù),這時(shí)可采用服務(wù)器主動向客戶端推送數(shù)據(jù)的方式。其基本流程如下:
(1)服務(wù)器端在某個(gè)事件(如Page_Load事件、DataGfid控件的SelectedlndexChange事件)發(fā)生時(shí),執(zhí)行相應(yīng)的處理程序,在此程序中利用Response.Write()語句,將服務(wù)器中的數(shù)據(jù),寫到一系列的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)客戶端再在某個(gè)事件觸發(fā)時(shí),執(zhí)行相應(yīng)的腳本程序,從這一系列的HTML語句中,獲取服務(wù)器端下發(fā)的數(shù)據(jù)。參考前述各策略所用方法,可將下發(fā)數(shù)據(jù)保存到文本文件、Excel文件、MDB文件、Table對象或其他位置。其核心語句有:
var oXH=FormLove.hXH.value;//獲取下發(fā)數(shù)據(jù)
Form2 txtXh.value oXH;
//保存到HTML型控件,也可保存到其他位置
(3)對緩存在客戶端的數(shù)據(jù)進(jìn)行操作。方法見前述各策略。
(4)提交數(shù)據(jù)。實(shí)現(xiàn)方法見前述各策略,如“策略IN”。
以上過程,實(shí)現(xiàn)了服務(wù)器端控件與客戶端控件的雙向交流,即服務(wù)器端控件可將數(shù)據(jù)傳遞給HTML型控件;通過表單中的Action選項(xiàng),HTML型控件可將數(shù)據(jù)傳遞給服務(wù)器端控件。
2.6策略六:在客戶端實(shí)現(xiàn)服務(wù)器端的某些功能
當(dāng)將服務(wù)器端的數(shù)據(jù)緩存到客戶端后,還可將相關(guān)的處理程序,遷移到客戶端執(zhí)行,進(jìn)一步減輕服務(wù)器負(fù)擔(dān),大大增強(qiáng)B/S模式中客戶端的處理能力,因此在某種程度上具有網(wǎng)格和分布式程序設(shè)計(jì)的思想。其基本步驟如下:
(1)將相關(guān)處理功能轉(zhuǎn)換為可獨(dú)立執(zhí)行的程序,最好編寫為具有雙接口(dual interface)的COM型組件程序,使之既可以在Windows環(huán)境中執(zhí)行,也可以在Web環(huán)境中被腳本調(diào)用。
(2)將相應(yīng)程序壓縮并保存到ftp文件夾。
(3)將可執(zhí)行程序包下載到客戶端并解開。方法見“策略一”中的介紹。
(4)客戶端通過腳本程序調(diào)用這些程序。
①若是具有雙接口的COM型組件程序,使用啟動Excel時(shí)所使用的方法,即var myApp=new ActiveXObjec(\"myCommyApp\")。其中“myCom”表示組件程序myComexe,“myApp”表示其主類名,如在Delphi為TmyApp=classfftypedComObjectJmyApp)。
②若是普通的程序,如ftp.exe、rar.exe,則可參考如下語句去執(zhí)行:
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 結(jié)束語
將服務(wù)器端的相關(guān)數(shù)據(jù),緩存到客戶端的文本文件、Excel文件、Access文件與客戶端內(nèi)存中,在客戶端通過執(zhí)行腳本程序,啟動組件程序或其他程序,讀寫這些緩存在客戶端的數(shù)據(jù),減輕了服務(wù)器端的負(fù)擔(dān)。
同時(shí)將在服務(wù)器端執(zhí)行的某些處理程序遷移到客觀端,可以分擔(dān)服務(wù)器的負(fù)載。
這些方法稍作修改可應(yīng)用于JSP、ASP等Web程序中;同樣,這些方法稍作整理與推廣,可用于C/S模式系統(tǒng)向B/S模式的移植開發(fā)中。
注:本文中所涉及到的圖表、注解、公式等內(nèi)容請以PDF格式閱讀原文。