“Active Server Page (ASP)”應用程序的成功常常取決於對體系結構和設計這兩方面的取捨。考慮到 ASP 技術的范圍之廣和當前應用程序固有的復雜性,這種取捨是非常困難的。本文中,我將為您提供一些特定的指導方針,以助您成功開發基於 ASP 的應用程序。
我已將指導方針整理成一組開發原則。在評估解決方案和技術時,可以應用以下原則幫助您做出決策。以下原則是我長期以來從成功的開發模式所得的經驗積累。
建立命名約定並使目錄結構標准化,可以幫助您大大提高 ASP 應用程序的可讀性和可維護性。雖然目前尚無 ASP 應用程序的正式標准,許多開發人員還是建立了一些通用方式。在此,我將與您共享一些更為通用的方式。
因為 ASP 技術依靠腳本引擎進行工作,而且腳本具有類型不嚴密的天性,命名約定也很模糊。在類型非常嚴密的語言中,變量將按照它的實際類型進行聲明。在使用 ASP 技術時,通常按照處理變量的方式(而不是其實際數據類型)在 ASP 代碼中聲明變量。例如,在使用“Visual Basic(R) Scripting Edition (VBScript)”時,盡管所有的 VBScript 變量都是 Variant,你還是會將成功標志聲明為 bSuccess(b 代表布爾型),而不是 vSuccess(v 代表 Variant)。
下表是一些通行的命名約定。
變量前綴:
數據庫對象的變量前綴:
范圍及前綴的用法:
Knowledge Base (KB) 中的一篇文章“Q110264 INFO: Microsoft Consulting Services Naming Conventions for Visual Basic”(英文)對命名約定提供了真知灼見。
盡可能采用目錄結構為您的各個應用程序部件提供始終如一的位置。您應用程序的實際目錄結構當然由您自己決定,但通常是將圖像、文檔、include 文件和組件分別放置在單獨的目錄中。以下是簡單 ASP 應用程序目錄結構示例。
目錄結構示例:
\SimpleAspApp \Docs \Images \Includes
一個好的目錄結構允許您有選擇地應用 NTFS 權限。您還可以從 ASP 應用程序內部使用相對路徑。例如,可以使用以下代碼,從位於 SimpleAspApp 目錄的 default.asp 頁,引用 Includes 目錄中的 include 文件 top.asp:
./includes/top.asp
注意我的 include 文件的擴展名是 .asp,而不是 .inc。這樣做是出於安全方面的考慮,而且使用 .asp 擴展名(而不是 .inc),還能夠在 Visual InterDev(R) 中使用彩色編碼。
有關結構化 ASP 應用程序的其他一些提示和技巧,請參閱文章“ASP Conventions”(英文)。
ASP 將在服務下運行。設計 ASP 應用程序時,您馬上會面臨在桌面應用程序中不會遇到的安全環境和線程問題。在桌面環境中,通常只處理作為交互式用戶運行的單線程執行,而且有權訪問當前的桌面系統。在“Internet 信息服務 (IIS)”中,模擬不同用戶環境的多個客戶機線程調用您的應用程序,而且您的應用程序被限於“系統”桌面。
這對您來說意味著什麼?請學習 IIS 的安全模式。還要提醒您:僅因為某些東西能在 Visual Basic IDE 下能夠正常運行,並不意味著它就能在 ASP 技術中安全運行。Visual Basic IDE 並沒有准確地模擬運行時環境。常見的設計錯誤包括:在 ASP 技術中使用需要用戶界面的 .OCX 控件,使用對線程來說不安全的組件,和使用要求特殊的用戶上下文的組件。要避免的一個最簡單的問題,就是從應用程序中試圖訪問 HKEY_CURRENT_USER (HKCU) 注冊表項(例如,不要調用 Visual Basic 的 GetSetting 和 SaveSetting 函數,它們都依賴於 HKCU)。同樣,不要出現需要用戶進行人機交互的消息框或其他對話框。
以下文章是有關 ASP 技術中的安全和驗證問題的相當不錯的入門讀物:
ASP 技術通過生成 HTML 輸出提供了表示服務。簡而言之,它會生成用戶界面。您需要將商務邏輯從 ASP 表示腳本中分隔開來。即使您不使用 COM 組件將商務邏輯從 ASP 代碼中分隔開來,至少也要將商務邏輯分隔到函數和 include 文件中,以提高可維護性、可讀性和可重用性。在需要排除故障和隔離問題時,您還能體會模塊化設計方法的好處。
調用腳本內部調用函數和方法,可避免代碼亂作一團,並能在 ASP 應用程序中添加結構。下面舉例說明從 ASP 代碼中,將邏輯分離到方法調用中:
lt;% Main() MyBizMethod() ... Sub Main() GetData() DisplayData() End Sub %>
在使用包含 ASP 功能的技術時,可以應用這一原則。下面舉一個使用 Visual Basic WebClass 時的例子,說明如何使用這一原則:
常見的問題是,從桌面系統到服務器的過渡。許多具有桌面系統背景的開發人員從來沒有為服務器的一些問題和資源共享擔心過。在傳統的桌面應用程序中,連接到服務器是個耗時的過程。為了改善用戶的體驗,通常采用盡早獲取資源和推遲釋放資源的方法。例如,許多應用程序會在它的整個運行時間內始終連接著數據庫。
這種方式在傳統的桌面應用程序中能夠正常工作其原因是用戶數量非常明確,容易加以控制,並且後端與前端緊密連接。然而,對於當前的 Web 應用程序,這種方式已經不可行了,其原因是有限的服務器資源將面對越來越多的用戶。為了使您的應用程序能夠應付用戶的增加,您需要盡晚獲取資源,盡早釋放資源。
共用有助於增加這一方式的有效性。通過共用,多個用戶能夠共享資源,而且等待時間最少,對服務器的影響也最小。例如,在處理數據庫時,ODBC 連接共用和 OLEDB 資源共用可以實現從共用池中選擇連接,最大程度地減少連接數據庫的開銷。
有關共用 ADO 的詳細信息,請參閱“Pooling in Microsoft Data Access Components”(英文)。
盡管 HTTP 協議是無狀態的,ASP 開發人員還是會經常使用 ASP 功能內置的狀態保持機制。例如,使用 ASP 技術內置的 Application 對象,開發人員所保存的資源能夠為應用程序的所有用戶共享。通過使用 ASP 內置的 Session 對象,開發人員只為單個用戶保存資源。
盡管聽起來在 ASP 技術的 Session 對象中保存信息是一個非常方便的保持狀態的方式,然而這一方式付出的代價太大,而且它也可能成為對可伸縮性的最大的限制因素之一。應用程序的可伸縮性本質上是隨著用戶數目的增長能夠繼續保持其性能的能力。而對於每一用戶,在會話超時或被放棄之前,Session 對象都會消耗服務器的資源。會話還會將您捆綁到一台服務器上,從而限制您利用 Web 集群的功能。請盡可能不要使用 ASP Session 對象進行狀態管理。如果您完全沒有使用會話,您就可以禁用 Web 應用程序的 Session 狀態(請參閱 IIS 文檔)。否則,您可以使用下述語句,針對每一頁禁用 Session 狀態:
<%@ENABLESESSIONSTATE=False %>
對於一些簡單的數據,您可以使用 QueryString cookie 或隱藏的窗體域保持 ASP 請求間的狀態。然後,對於更為復雜的信息,通常推薦您使用數據庫。一般所采用的方式是生成某一特有的標識符,然後發送到每一個發出請求的客戶機,並保存為隱藏的窗體域。在隨後的請求中,這一特有的標識符被用於在數據庫中查找與該用戶相關的狀態信息。這一方式提供了更高的可伸縮性和更為簡潔明了的代碼。
有關使用 QueryString cookie 和隱藏的窗體域的詳細信息,請參閱“Q175167 HOWTO: Persisting Values Without Sessions”(英文)。
在創建 ASP 技術的對象時,您可以選擇 <OBJECT> 標記、Server.CreateObject 和 CreateObject 三種方式。每項技術的行為略有不同。盡管在 IIS 4.0 中,使用 <OBJECT> 標記或 CreateObject 比 Server.CreateObject 略具性能優勢,我們一般還是推薦使用 Server.CreateObject, 以便於 ASP 應用程序認知您的對象。(注意在 IIS 5.0 中,前兩項與 Server.CreateObject 相比,已經沒有性能優勢。)
<OBJECT> 標記僅在調用第一個方法時才會創建組件,因此能夠節省資源。Server.CreateObject 使用 ASP 技術內置的 Server 對象創建組件。實質上,它只是執行了 CoCreateInstance,但是 ASP 卻能夠認知這一對象。同時,還將調用 ASP 技術的傳統的 OnStartPage 和 OnEndPage。(注意最好在 IIS 4.0 或者更高版本中使用 ObjectContext)。如果您只是使用 CreateObject,您將越過 ASP 技術而直接使用 Scripting 引擎。
以下是一個可能出現的例外情況:當您通過防火牆進行調用時,您可能需要調用 CreateObject 而不是 Server.CreateObject。詳細信息,請參閱“Q193230 - PRB: Server.CreateObject Fails when Object is Behind Firewall”(英文)。
確保在您所有的 ASP 應用程序中都包含了錯誤處理過程。而且,確保您提供了有用的診斷信息。我還沒有碰到有哪個人抱怨錯誤信息太具有說明性了。請確保在錯誤日志中包含以下信息:
因為將在 ASP 下運行,您可能希望將這些信息寫到文件或 NT 的事件日志。您還可以創建記錄關鍵的應用程序事件的應用程序事件日志,以備診斷應用程序錯誤時使用。
以下文章提供了有關錯誤處理技術的詳細信息:
浏覽器並不是准確的測試方式,它只能向您展示應用程序可能的用途。請針對您的應用程序設置特定的性能目標,並使用 Web Application Stress Tool 等負載工具進行壓力測試。您需要自己決定您的環境所能接受的條件,以下是一些幫助您啟動測試過程的通用指導方針:
將測試環境與實際運行的環境相匹配,甚至防火牆也不例外。這聽起來代價很高,但我曾經聽說過開發人員因為沒有考慮到防火牆,而丟失了工作。
有關使用 Web Application Stress Tool 測試 ASP 應用程序的詳細信息,請參閱“I Can't Stress It Enough -- Load Test Your ASP Application”(英文)。
使用隔離功能保護您的應用程序過程能夠極大地增強服務器的穩定性。談到 Internet 應用程序,是否使用隔離功能的後果可能會有巨大的差別:一個是應用程序崩潰,一個是服務器當機。保護主 IIS 進程 (InetInfo.exe) 通常會排在優先級列表的較高位置。在您使用組件時,這一點尤為突出。
通常所采用的保護主 ISS 進程的技術是使 Web 應用程序運行在各自的內存空間中。在 Internet Services Manager 中,您可以針對每一個 Web 設置這一選項。雖然因對進程進行編組而開銷的系統資源會對性能有些微的影響,但對應用程序所起的保護作用值得付出這一代價。 在 IIS 4.0 下,您可以采用進程內 (in-process) 和進程外(out-of-process,OOP)兩種方式運行應用程序。OOP 應用程序會運行在新的 Mtx.exe 實例中。在 IIS 5.0 下,您還能使用其他的隔離選項。可以將隔離級別設置為“低”(對 Inetinfo.exe 來說是進程內應用程序)、“中”(DllHost.exe 共享實例)或“高”(Dllhost.exe的非共享實例)。
除了將 Web 應用程序隔離在它們自己的內存空間中之外,您可能還希望隔離不信任的組件。不信任的組件通常是在實際環境中沒有通過測試時間的考驗的組件。您可以在 Server 包中運行這些組件,這樣它們會運行在新的 Dllhost.exe 實例中。
一般而言,如果要在性能和保護措施之間采取中庸之道,方式如下:在“高”隔離狀態運行 Web 應用程序,在庫包中運行組件。這種方式最大限度地減少了編組開支,同時在進程之間提供了最強的保護作用。
詳細信息,請參閱文章“Server Reliability Through Process Isolation”(英文)。
在 IIS 4.0 下,針對每個受 MTS 管理的處理器,ASP 的默認共用組是 10 個線程。在 IIS 5.0 中,默認值是 20。這就意味著每一線程都是一份潛在的寶貴資源,能夠處理多個客戶機請求。您同樣需要避免調用會出現阻塞的方法,如進行大的數據庫調用。如果您有要執行這種操作的工作,它將阻止 ASP 應用程序將響應快速返回到客戶機,則請考慮使用隊列功能。例如,在 NT 4.0 中,可以使用 MSMQ。在 Windows 2000 中,可以使用 Queued Components(排隊組件)。
在會話中不要存儲 Single-threaded Apartment (STA) 組件,這種方式的一個共同缺陷是會填滿會話范圍中的 Visual Basic 對象。會將用戶鎖定到某一線程,與線程共用組的目的背道而馳。潛在的用戶會被阻塞在其他用戶的後面,等待創建他們組件的線程變得有效。您應該采用別的方式,設計能基於每一頁進行創建和破壞的無狀態組件。
快速提示:確保已在服務器上禁用了 ASP Script Debugging 功能(使用 Internet Services Manager)。如果啟用了 ASP Script Debugging,則 ASP 的執行過程將被鎖定到某一線程。
詳細信息,請參閱以下文章:
創建 ASP 應用程序需要相當寬廣的知識面。ASP 應用程序所面臨的一個挑戰是目前沒有通用的規則(這也正是樂趣的一部分)。另外一個問題是許多開發人員接觸 Internet 開發之前是從事桌面系統的開發工作。通過在您的 ASP 開發工作中應用上述規則,您有希望避免犯下代價巨大的錯誤,並能開發出相當不錯的 ASP 應用程序。