小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

基于.NET的Web應(yīng)用框架構(gòu)建模式

 liuqg 2006-03-14
基于.NET的Web應(yīng)用框架構(gòu)建模式
[簡(jiǎn)介]
本文對(duì)應(yīng)于Web表示模式集群,文章的前半部分重筆墨的描述了MVC模式的架構(gòu)、設(shè)計(jì)及其ASP.NET實(shí)現(xiàn),而在更加復(fù)雜的系統(tǒng)中,隨后提出了Page Controller(頁(yè)面控制器)和Front Controller(前端控制器)作為MVC實(shí)現(xiàn)的補(bǔ)充,最后,簡(jiǎn)要介紹了Web表示模式集群的另外兩個(gè)模式:Intercepting Filter(篩選器)和Page Cache(頁(yè)面緩存)模式。

“體系結(jié)構(gòu)設(shè)計(jì)者的第一個(gè)作品往往比較簡(jiǎn)練和干凈。他知道自己并不了解正在進(jìn)行的工作,因此他小心謹(jǐn)慎地設(shè)計(jì)它。在他設(shè)計(jì)第一個(gè)作品時(shí),會(huì)進(jìn)行多次修飾和潤(rùn)色。這些會(huì)留到“下一次”使用……這第二個(gè)系統(tǒng)是他曾經(jīng)設(shè)計(jì)的最危險(xiǎn)的系統(tǒng)……一般趨勢(shì)是,在設(shè)計(jì)第二個(gè)系統(tǒng)時(shí),將會(huì)使用在第一個(gè)作品中被小心擱置在一邊的所有思路和修飾,從而導(dǎo)致設(shè)計(jì)過(guò)了頭。”
—Frederick P. Brooks, Jr.發(fā)表于1972年的The Mythical Man Month(人月神話)。

Web上建立的第一個(gè)系統(tǒng)是簡(jiǎn)單地鏈接在一起的靜態(tài)HTML頁(yè)面,以便在分散的小組之間共享文檔。隨著用戶的使用量增加,可響應(yīng)用戶輸入的動(dòng)態(tài)網(wǎng)頁(yè)日益普遍。早期的動(dòng)態(tài)頁(yè)面一般是以通用網(wǎng)關(guān)接口(CGI)腳本的形式編寫(xiě)的。這些CGI腳本不僅包含用來(lái)確定在響應(yīng)用戶輸入時(shí)應(yīng)當(dāng)顯示什么內(nèi)容的業(yè)務(wù)邏輯,而且還會(huì)生成表示HTML。隨著對(duì)更復(fù)雜邏輯需求的增加,對(duì)更豐富、更生動(dòng)的表示形式的需求也隨之增加。這種增加了的復(fù)雜性給CGI編程模型帶來(lái)了挑戰(zhàn)。
不久,基于頁(yè)面的開(kāi)發(fā)手段(如ASP和JSP)出現(xiàn)了。這些新方法允許開(kāi)發(fā)人員將腳本直接嵌入到HTML面中,從而簡(jiǎn)化了編程模型。當(dāng)這些嵌入的腳本應(yīng)用程序變得更復(fù)雜時(shí),開(kāi)發(fā)人員希望在頁(yè)面級(jí)別將業(yè)務(wù)邏輯與表示邏輯分開(kāi)。為適應(yīng)這一要求,隨之出現(xiàn)了具有幫助器對(duì)象和代碼隱藏頁(yè)面策略的標(biāo)記庫(kù)。然后,又出現(xiàn)了提供動(dòng)態(tài)配置站點(diǎn)導(dǎo)航和命令調(diào)度程序的精細(xì)框架,但所有這一切都是以增加復(fù)雜性為代價(jià)的。假設(shè)現(xiàn)在有大量的Web表示可選方案,如何為您的應(yīng)用程序選擇適當(dāng)?shù)腤eb表示設(shè)計(jì)策略?

是否真的有一個(gè)設(shè)計(jì)策略能夠適應(yīng)所有的情況?很不幸,在軟件設(shè)計(jì)中,消除過(guò)多的冗余和過(guò)度的復(fù)雜性是一個(gè)競(jìng)爭(zhēng)性需求,很難能夠真正做到兩者之間的平衡。您可以從包含嵌入腳本的簡(jiǎn)單頁(yè)面開(kāi)始設(shè)計(jì)工作,但很快業(yè)務(wù)邏輯就會(huì)不斷重復(fù)出現(xiàn)在各個(gè)文件中,從而導(dǎo)致系統(tǒng)難以維護(hù)和擴(kuò)展。通過(guò)將該邏輯移到一組協(xié)作組件中,可以消除冗余,但是這樣做會(huì)增加解決方案的復(fù)雜性。另一方面,您的設(shè)計(jì)工作可以從設(shè)計(jì)用來(lái)提供標(biāo)記庫(kù)、動(dòng)態(tài)配置和命令調(diào)度程序的框架入手,可是這樣雖然能夠消除冗余代碼,但它會(huì)大大增加系統(tǒng)的復(fù)雜性,而這通常是不必要的。
而如何考慮各個(gè)方面的需求,提出一個(gè)最合適我們應(yīng)用的Web表示策略呢?這需要在復(fù)雜解決方案(支持將來(lái)可能發(fā)生變化的情形)和簡(jiǎn)單解決方案(滿足目前的要求)之間做出抉擇,原則上適當(dāng)增加成本是可取的,而過(guò)多增加成本卻是不可取的。那么廢話少說(shuō),我們就從“簡(jiǎn)單”開(kāi)始吧。

MVC(模型—視圖—控制)
許多計(jì)算機(jī)系統(tǒng)的用途都是從數(shù)據(jù)存儲(chǔ)檢索數(shù)據(jù)并將其顯示給用戶。在用戶更改數(shù)據(jù)之后,系統(tǒng)再將更新內(nèi)容存儲(chǔ)到數(shù)據(jù)存儲(chǔ)中。因?yàn)殛P(guān)鍵的信息流發(fā)生在數(shù)據(jù)存儲(chǔ)和用戶界面之間,所以您可能傾向于將這兩部分綁在一起,以減少編碼量并提高應(yīng)用程序性能。但是,這種看起來(lái)自然而然的方法有一些大問(wèn)題。一個(gè)問(wèn)題是,用戶界面的更改往往比數(shù)據(jù)存儲(chǔ)系統(tǒng)的更改頻繁得多。將數(shù)據(jù)和用戶界面這兩部分耦合在一起帶來(lái)的另一個(gè)問(wèn)題是,業(yè)務(wù)應(yīng)用程序往往會(huì)并入遠(yuǎn)不止數(shù)據(jù)傳輸功能的其他業(yè)務(wù)邏輯。如何讓W(xué)eb應(yīng)用程序的用戶界面功能實(shí)現(xiàn)模塊化,以便您可以輕松地單獨(dú)修改各個(gè)部分?
Model-View-Controller正是這樣的模式,它實(shí)現(xiàn)功能模塊和顯示模塊的分離,使得應(yīng)用程序更加可維護(hù),可擴(kuò)展,可移植和可復(fù)用,它最初是Trygve Reenskaug在二十世紀(jì)七十年代末為Smalltalk平臺(tái)開(kāi)發(fā)的框架[Fowler03],而發(fā)展到目前為止,已經(jīng)形成了一個(gè)非常成熟的模式。

MVC解決方案
Model-View-Controller (MVC)模式基于用戶輸入,將域的建模、顯示和操作分為三個(gè)獨(dú)立的類[Burbeck92]:
q 模型。模型用于管理應(yīng)用程序域的行為和數(shù)據(jù),并響應(yīng)為獲取其狀態(tài)信息(通常來(lái)自視圖)而發(fā)出的請(qǐng)求,還會(huì)響應(yīng)更改狀態(tài)的指令(通常來(lái)自控制器)。
q 視圖。視圖用于管理信息的顯示。
q 控制器??刂破饔糜诮忉層脩舻氖髽?biāo)和鍵盤(pán)輸入,以通知模型和/或視圖進(jìn)行相應(yīng)的更改。
視圖和控制器都依賴于模型。但是,模型既不依賴于視圖,也不依賴于控制器。這是分離的主要優(yōu)點(diǎn)之一。這樣的分離允許模型在獨(dú)立于可視表示功能的情況下建立和測(cè)試。在許多胖客戶端應(yīng)用程序中,視圖與控制器的分離是次要的,實(shí)際上,許多用戶界面框架將角色實(shí)現(xiàn)為一個(gè)對(duì)象。另一方面,在Web應(yīng)用程序中,視圖(瀏覽器)與控制器(處理HTTP請(qǐng)求的服務(wù)器端組件)的分離是很好定義的。
Model-View-Controller是一個(gè)用于將用戶界面邏輯與業(yè)務(wù)邏輯分離開(kāi)來(lái)的基礎(chǔ)設(shè)計(jì)模式。遺憾的是,此模式的普及導(dǎo)致了許多錯(cuò)誤的描述。特別是在不同的上下文中,術(shù)語(yǔ)“控制器”已經(jīng)用于意指不同的事物。幸運(yùn)的是,Web應(yīng)用程序的出現(xiàn)已經(jīng)幫助消除了一些不明確性,因?yàn)橐晥D與控制器的分離是如此明顯。

MVC的變型
在Application Programming in Smalltalk-80: How to use Model-View-Controller (MVC) [Burbeck92]中,Steve Burbeck描述了MVC的兩個(gè)變型:被動(dòng)模型和主動(dòng)模型。
當(dāng)一個(gè)控制器以獨(dú)占方式操作模型時(shí),將使用被動(dòng)模型。控制器將修改模型,然后通知視圖:模型已經(jīng)更改,應(yīng)該進(jìn)行刷新(見(jiàn)圖2)。此情況下的模型完全獨(dú)立于視圖和控制器,這意味著模型無(wú)法報(bào)告其狀態(tài)更改。HTTP協(xié)議是此方案的示例。瀏覽器沒(méi)有從服務(wù)器獲取異步更新的簡(jiǎn)單方法。瀏覽器顯示視圖并對(duì)用戶輸入作出響應(yīng),但是它不會(huì)檢測(cè)服務(wù)器上的數(shù)據(jù)更改。僅當(dāng)用戶顯式請(qǐng)求刷新時(shí),才會(huì)詢問(wèn)服務(wù)器是否發(fā)生了更改。
當(dāng)模型更改狀態(tài)而不涉及控制器時(shí),將使用主動(dòng)模型。當(dāng)其他資源正在更改數(shù)據(jù)并且更改必須反映在視圖中時(shí),可能會(huì)發(fā)生這種情況。以股票報(bào)價(jià)機(jī)的顯示為例。您從外部源接收股票數(shù)據(jù),并希望當(dāng)股票數(shù)據(jù)更改時(shí)更新視圖(例如,報(bào)價(jià)機(jī)數(shù)據(jù)區(qū)和警告窗口)。因?yàn)橹挥心P蜋z測(cè)對(duì)其內(nèi)部狀態(tài)的更改(在這些更改發(fā)生時(shí)),所以模型必須通知視圖刷新顯示。
但是,使用MVC模式的一個(gè)目的是使模型獨(dú)立于視圖。如果模型必須將更改通知視圖,則會(huì)重新帶來(lái)您希望避免的依賴性。幸運(yùn)的是,Observer模式[Gamma95]提供了這樣的機(jī)制:提醒其他對(duì)象注意狀態(tài)的更改,而不會(huì)導(dǎo)致對(duì)這些對(duì)象的依賴性。各個(gè)視圖實(shí)現(xiàn)Observer接口,并向模型注冊(cè)。模型將跟蹤由訂閱更改的所有觀察器組成的列表。當(dāng)模型發(fā)生改變時(shí),模型將會(huì)遍歷所有已注冊(cè)的觀察器,并將更改通知它們。此方法通常稱為“發(fā)布-訂閱”。模型從不需要有關(guān)任何視圖的特定信息。實(shí)際上,在需要將模型更改通知控制器的情況下(例如,啟用或禁用菜單選項(xiàng)),控制器必須做的全部工作是實(shí)現(xiàn)Observer接口并訂閱模型更改。對(duì)于存在許多視圖的情況,定義多個(gè)主體是有意義的,其中每個(gè)主體都描述了特定類型的模型更改。然后,每個(gè)視圖都只能訂閱與視圖有關(guān)的更改類型。圖3顯示了使用Observer的主動(dòng)MVC的結(jié)構(gòu),以及觀察器如何將模型與直接引用視圖隔離開(kāi)來(lái)。
圖4說(shuō)明當(dāng)模型發(fā)生改變時(shí)Observer如何通知視圖??上У氖牵诮y(tǒng)一建模語(yǔ)言(UML)序列圖中,沒(méi)有好的方法來(lái)演示模型與視圖的分離,因?yàn)樵搱D表示的是對(duì)象的實(shí)例而不是類和接口。
MVC的ASP.NET實(shí)現(xiàn)
為了解釋如何在ASP.NET中實(shí)現(xiàn)Model-View-Controller模式,并說(shuō)明在軟件中分離模型、視圖和控制器角色的好處,下面的示例將一個(gè)沒(méi)有分離所有三個(gè)角色的單頁(yè)面解決方案重構(gòu)為分離這三個(gè)角色的解決方案。示例應(yīng)用程序是一個(gè)帶有下拉列表的網(wǎng)頁(yè)(如欄下圖所示),該頁(yè)面顯示了存儲(chǔ)在數(shù)據(jù)庫(kù)中的記錄。
利用Microsoft Visual Studio(r) .NET開(kāi)發(fā)系統(tǒng)的代碼隱藏功能,可以很容易地將表示(視圖)代碼與Model-Controller代碼分離開(kāi)來(lái)。每個(gè)ASP.NET頁(yè)都有一種機(jī)制,這種機(jī)制允許在單獨(dú)的類中實(shí)現(xiàn)從網(wǎng)頁(yè)調(diào)用的方法。該機(jī)制是通過(guò)Visual Studio .NET提供的,它有許多優(yōu)點(diǎn),例如Microsoft IntelliSense(r)技術(shù)。當(dāng)您使用代碼隱藏功能來(lái)實(shí)現(xiàn)網(wǎng)頁(yè)時(shí),可以使用IntelliSense來(lái)顯示網(wǎng)頁(yè)后面的代碼中所使用的對(duì)象的可用方法列表。IntelliSense不適用于.aspx頁(yè)。與此同時(shí),為了展現(xiàn)Model-Controller的分離,對(duì)于數(shù)據(jù)庫(kù)操作提取了DatabaseGateway,這樣就實(shí)現(xiàn)了三者的完整分離。
視圖
<%@ Page language="c#" Codebehind="Solution.aspx.cs"
AutoEventWireup="false" Inherits="Solution" %>
<html>
<head>
<title>解決方案</title>
</head>
<body>
<form id="Solution" method="post" runat="server">
<h3>錄音</h3>
選擇錄音:<br/>
<asp:dropdownlist id="recordingSelect" runat="server" />
<asp:button id="submit" runat="server" text="Submit"
enableviewstate="False" />
<p/>
<asp:datagrid id="MyDataGrid" runat="server" width="700"
backcolor="#ccccff" bordercolor="black" showfooter="false"
cellpadding="3" cellspacing="0" font-name="Verdana" font-size="8pt"
headerstyle-backcolor="#aaaadd" enableviewstate="false" />
</form>
</body>
</html>

模型
using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;
public class DatabaseGateway
{
public static DataSet GetRecordings()
{
String selectCmd = "select * from Recording";

SqlConnection myConnection =
new SqlConnection(
"server=(local);database=recordings;Trusted_Connection=yes");
SqlDataAdapter myCommand = new SqlDataAdapter(selectCmd, myConnection);

DataSet ds = new DataSet();
myCommand.Fill(ds, "Recording");
return ds;
}

public static DataSet GetTracks(string recordingId)
{
String selectCmd =
String.Format(
"select * from Track where recordingId = {0} order by id",
recordingId);

SqlConnection myConnection =
new SqlConnection(
"server=(local);database=recordings;Trusted_Connection=yes");
SqlDataAdapter myCommand = new SqlDataAdapter(selectCmd, myConnection);

DataSet ds = new DataSet();
myCommand.Fill(ds, "Track");
return ds;
}

控制
using System;
using System.Data;
using System.Collections;
using System.Web.UI.WebControls;

public class Solution : System.Web.UI.Page
{
protected System.Web.UI.WebControls.Button submit;
protected System.Web.UI.WebControls.DataGrid MyDataGrid;
protected System.Web.UI.WebControls.DropDownList recordingSelect;

private void Page_Load(object sender, System.EventArgs e)
{
if(!IsPostBack)
{
DataSet ds = DatabaseGateway.GetRecordings();
recordingSelect.DataSource = ds;
recordingSelect.DataTextField = "title";
recordingSelect.DataValueField = "id";
recordingSelect.DataBind();
}
}

void SubmitBtn_Click(Object sender, EventArgs e)
{
DataSet ds =
DatabaseGateway.GetTracks(
(string)recordingSelect.SelectedItem.Value);

MyDataGrid.DataSource = ds;
MyDataGrid.DataBind();
}

#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: 此調(diào)用是 ASP.NET Web 窗體設(shè)計(jì)器所必需的。
//
InitializeComponent();
base.OnInit(e);
}

/// <summary>
/// 設(shè)計(jì)器支持所必需的方法 - 不要使用代碼編輯器修改
/// 此方法的內(nèi)容。
/// </summary>
private void InitializeComponent()
{
this.submit.Click += new System.EventHandler(this.SubmitBtn_Click);
this.Load += new System.EventHandler(this.Page_Load);

}
#endregion
}

以上示例簡(jiǎn)單的說(shuō)明了ASP.NET的MVC實(shí)現(xiàn),在實(shí)際項(xiàng)目中,商務(wù)邏輯遠(yuǎn)遠(yuǎn)不止這樣,但是上述的代碼展現(xiàn)了一個(gè)基本的模型,在增加了代碼和復(fù)雜度的同時(shí)也帶來(lái)了顯而易見(jiàn)的好處,如:模塊依賴的降低、代碼重復(fù)的減少、職責(zé)和問(wèn)題的分離、代碼的可測(cè)試性等等。
到現(xiàn)在您是否決定了使用Model-View-Controller (MVC)模式來(lái)將動(dòng)態(tài)Web應(yīng)用程序的用戶界面組件與業(yè)務(wù)邏輯分隔開(kāi)來(lái),要構(gòu)建的應(yīng)用程序?qū)⒁詣?dòng)態(tài)方式構(gòu)造網(wǎng)頁(yè),但是目前的頁(yè)面導(dǎo)航都是基于靜態(tài)導(dǎo)航的形式。
在更加復(fù)雜的應(yīng)用系統(tǒng)中,如何考慮盡可能避免導(dǎo)航代碼的重復(fù),甚至考慮基于可配置的規(guī)則來(lái)動(dòng)態(tài)確定頁(yè)面導(dǎo)航,那么Page Controller和Front Controller某種意義來(lái)說(shuō)是對(duì)于MVC模式在更加復(fù)雜的系統(tǒng)的優(yōu)化。

中等復(fù)雜程度的優(yōu)化—Page Controller(頁(yè)面控制器)
使用Page Controller模式接受來(lái)自頁(yè)面請(qǐng)求的輸入、調(diào)用請(qǐng)求對(duì)模型執(zhí)行的操作以及確定應(yīng)用于結(jié)果頁(yè)面的正確視圖。分隔調(diào)度邏輯和所有視圖相關(guān)代碼。如果合適,創(chuàng)建用于所有頁(yè)面控制器的公用基類,以避免代碼重復(fù)并提高一致性和可測(cè)試性。圖5顯示了頁(yè)面控制器與模型和視圖的關(guān)系。
頁(yè)面控制器可接收頁(yè)面請(qǐng)求、提取所有相關(guān)數(shù)據(jù)、調(diào)用對(duì)模型的所有更新以及向視圖轉(zhuǎn)發(fā)請(qǐng)求。而視圖又將根據(jù)該模型檢索要顯示的數(shù)據(jù)。定義獨(dú)立頁(yè)面控制器將分隔模型與Web請(qǐng)求細(xì)節(jié)(例如會(huì)話管理,或使用查詢字符串或隱藏表單域向頁(yè)面?zhèn)鬟f參數(shù))。按照這種基本形式,為Web應(yīng)用程序中的每個(gè)鏈接創(chuàng)建控制器。控制器因而將變得非常簡(jiǎn)單,因?yàn)槊看蝺H須考慮一個(gè)操作。
為每個(gè)網(wǎng)頁(yè)(或操作)創(chuàng)建獨(dú)立控制器可能會(huì)導(dǎo)致大量代碼重復(fù)。因此應(yīng)該創(chuàng)建BaseController類以合并驗(yàn)證參數(shù)(請(qǐng)參閱圖6)等公用函數(shù)。每個(gè)獨(dú)立頁(yè)面控制器都可以從BaseController繼承此公用功能。除了從公用基類繼承之外,還可以定義一組幫助器類,控制器可以調(diào)用這些類來(lái)執(zhí)行公用功能。
大多數(shù)情況下,頁(yè)面控制器取決于基于HTTP的Web請(qǐng)求的具體細(xì)節(jié)。因此,頁(yè)面控制器代碼通常包含對(duì)HTTP頭、查詢字符串、表單域、多部分表單請(qǐng)求等的引用。因此在Web應(yīng)用程序框架之外測(cè)試控制器代碼非常困難。唯一方法是通過(guò)模擬HTTP請(qǐng)求和分析結(jié)果來(lái)測(cè)試控制器。這種類型的測(cè)試既費(fèi)時(shí)且易出錯(cuò)。因此,要提高可測(cè)試性,可以將依賴Web的代碼和不依賴Web的代碼分別放入兩個(gè)單獨(dú)類中(請(qǐng)參閱圖7),這是Page Controller的變體實(shí)現(xiàn)。
Page Controller是大多數(shù)動(dòng)態(tài)Web應(yīng)用程序的默認(rèn)實(shí)現(xiàn)方式,它簡(jiǎn)單,Web應(yīng)用框架內(nèi)置,可擴(kuò)展性及其開(kāi)發(fā)人員責(zé)任的分隔等等優(yōu)點(diǎn)使其在Web開(kāi)發(fā)得到廣泛的應(yīng)用,不過(guò)每頁(yè)面一控制器、較深的繼承樹(shù)和對(duì)于Web框架的依賴等等也是其比較明顯的限制。

高度復(fù)雜的優(yōu)化
—Front Controller(前端控制器)
Front Controller通過(guò)讓單個(gè)控制器負(fù)責(zé)傳輸所有請(qǐng)求,從而解決了在Page Controller中存在的分散化問(wèn)題。控制器本身通常分為以下兩部分實(shí)現(xiàn):處理程序和命令層次結(jié)構(gòu)(見(jiàn)圖8)。
處理程序具有以下兩項(xiàng)職責(zé):
1) 檢索參數(shù)。處理程序接收來(lái)自Web服務(wù)器的HTTP Post或Get請(qǐng)求,并從請(qǐng)求中檢索相關(guān)參數(shù)。
2) 選擇命令。處理程序首先使用請(qǐng)求中的參數(shù)選擇正確的命令,然后將控制權(quán)轉(zhuǎn)移給該命令以便執(zhí)行處理。
在前端控制器中,所有請(qǐng)求都通過(guò)單個(gè)(通常是兩部件)控制器來(lái)傳送??刂破鞯牡谝粋€(gè)部件是處理程序,第二個(gè)部件是Commands(命令)[Gof95]的層次。命令本身是控制器的一部分,代表控制器觸發(fā)的特定操作。在執(zhí)行該操作之后,命令選擇要使用哪個(gè)視圖來(lái)呈現(xiàn)頁(yè)面。通常,構(gòu)建的此控制器框架使用配置文件將請(qǐng)求映射到操作,因此,它在構(gòu)建之后便于更改。當(dāng)然,其缺點(diǎn)在于這種設(shè)計(jì)固有的復(fù)雜程度。

遺漏之后的補(bǔ)充
到目前為止,已經(jīng)完整地展示了Web表示模式中MVC的實(shí)現(xiàn)架構(gòu),同時(shí)在此技術(shù)上對(duì)于中等復(fù)雜和高度復(fù)雜的情況提出了Page Controller和Front Controller作為優(yōu)化的手段,在構(gòu)建Web表示的應(yīng)用程序,已經(jīng)給出了相對(duì)完整的解決方案,細(xì)心的讀者是否發(fā)現(xiàn),是不是還少了一點(diǎn)什么?在構(gòu)建Web應(yīng)用程序的時(shí)候,除了構(gòu)建一個(gè)“良構(gòu)”的系統(tǒng)(這表現(xiàn)在MVC的分離和系統(tǒng)的可擴(kuò)展),我們還需要考慮應(yīng)用程序的安全和性能,因此我們選取了Interceptiing Filter和Page Cache作為Web表示模式的補(bǔ)充內(nèi)容。

Intercepting Filter(篩選器)
如何圍繞Web頁(yè)面請(qǐng)求來(lái)實(shí)現(xiàn)公共的預(yù)處理和后處理步驟?這是篩選器需要解決的問(wèn)題,使用此模式,您創(chuàng)建一串可組合的篩選器,以便在Web頁(yè)面請(qǐng)求期間實(shí)現(xiàn)公共的預(yù)處理和后處理任務(wù)。
篩選器構(gòu)成了一系列獨(dú)立模塊,在將頁(yè)面請(qǐng)求傳遞到控制器對(duì)象之前,這些模塊可以鏈接在一起以執(zhí)行一組公共的處理步驟。因?yàn)楦鱾€(gè)篩選器實(shí)現(xiàn)的是完全相同的接口,所以它們彼此之間沒(méi)有顯式依賴性。因此,可以在不會(huì)影響現(xiàn)有篩選器的情況下添加新的篩選器。您甚至可以在部署時(shí)添加篩選器,方法是基于配置文件動(dòng)態(tài)地對(duì)它們進(jìn)行實(shí)例化。
對(duì)各個(gè)篩選器的設(shè)計(jì)應(yīng)該盡可能讓它們不對(duì)是否存在其他篩選器作出任何假設(shè)。這樣可以維護(hù)可組合性,即添加、刪除或重新排列篩選器的能力。此外,某些實(shí)現(xiàn)Intercepting Filter模式的框架不會(huì)保證篩選器的執(zhí)行順序。如果發(fā)現(xiàn)多個(gè)篩選器之間存在很強(qiáng)的相互依賴性,最好采取調(diào)用幫助器類的常規(guī)方法,因?yàn)檫@樣可以保證保留篩選器序列中的約束信息。Intercepting Filter的直接實(shí)現(xiàn)方式是一個(gè)篩選器鏈,這個(gè)篩選器鏈可以用來(lái)遍歷一個(gè)由所有篩選器組成的列表。Web請(qǐng)求處理程序在將控制權(quán)傳遞到應(yīng)用程序邏輯之前將首先執(zhí)行篩選器鏈。
當(dāng)Web服務(wù)器收到頁(yè)面請(qǐng)求時(shí),請(qǐng)求處理程序首先將控制權(quán)傳遞給FilterChain(篩選器鏈)對(duì)象。此對(duì)象維護(hù)著一個(gè)包含所有篩選器的列表,并按順序調(diào)用每個(gè)篩選器。FilterChain可以從配置文件中讀取篩選器順序,以實(shí)現(xiàn)部署時(shí)的可組合性。每個(gè)篩選器都有機(jī)會(huì)修改傳入請(qǐng)求。例如,它可以修改URL,或添加應(yīng)用程序要使用的頭字段。執(zhí)行完所有篩選器之后,"請(qǐng)求處理程序"將控制權(quán)傳遞給控制器,后者將執(zhí)行應(yīng)用程序功能(見(jiàn)圖12)。
因?yàn)樵谔幚鞼eb請(qǐng)求時(shí)通常需要有截取篩選器,所以大多數(shù)Web框架都為應(yīng)用程序開(kāi)發(fā)人員提供了將截取篩選器掛靠到請(qǐng)求-響應(yīng)過(guò)程中的機(jī)制。

Page Cache(頁(yè)面緩存)]
如果動(dòng)態(tài)生成的Web頁(yè)被頻繁請(qǐng)求并且構(gòu)建時(shí)需要耗用大量的系統(tǒng)資源,那么,如何才能改進(jìn)這類網(wǎng)頁(yè)的響應(yīng)時(shí)間?頁(yè)面緩存通過(guò)對(duì)從動(dòng)態(tài)網(wǎng)頁(yè)生成的內(nèi)容進(jìn)行緩存來(lái)提高請(qǐng)求響應(yīng)的吞吐量。默認(rèn)情況下,在ASP.NET中支持頁(yè)面緩存,但除非定義有效的過(guò)期策略,否則,不會(huì)對(duì)來(lái)自任何給定響應(yīng)的輸出進(jìn)行緩存。要定義過(guò)期策略,可以使用低級(jí)OutputCache API或高級(jí)@OutputCache指令。
頁(yè)面緩存的基本結(jié)構(gòu)是相對(duì)簡(jiǎn)單的。Web服務(wù)器維護(hù)包含預(yù)先生成的頁(yè)面的本地?cái)?shù)據(jù)存儲(chǔ)(見(jiàn)圖13)。
下面的序列圖闡明了頁(yè)面緩存可以改進(jìn)性能的原因。第一個(gè)序列圖(見(jiàn)圖2)描述尚未緩存所需頁(yè)面的初始狀態(tài)(即所謂的緩存未命中)。在這種情況下,Web服務(wù)器必須訪問(wèn)數(shù)據(jù)庫(kù),并生成HTML頁(yè),再將其存儲(chǔ)在緩存中,然后將它返回給客戶端瀏覽器。請(qǐng)注意,此過(guò)程比不進(jìn)行緩存的情況稍慢,因?yàn)樗鼒?zhí)行了下列額外步驟:
1. 確定頁(yè)面是否已緩存
2. 將頁(yè)面轉(zhuǎn)換為HTML代碼,然后存儲(chǔ)在緩存中

與數(shù)據(jù)庫(kù)訪問(wèn)和HTML生成相比,其中的任一步驟都不應(yīng)該花費(fèi)很長(zhǎng)時(shí)間。但是,因?yàn)樵诖饲闆r下需要進(jìn)行額外處理,所以您必須確保在系統(tǒng)完成與緩存未命中關(guān)聯(lián)的步驟之后連續(xù)多次命中緩存(如圖14所示)。
在圖15所示的緩存命中情況下,頁(yè)面已經(jīng)處于緩存中。通過(guò)跳過(guò)數(shù)據(jù)庫(kù)訪問(wèn)、頁(yè)面生成和頁(yè)面存儲(chǔ),緩存命中節(jié)省了循環(huán)。
在ASP.NET中可以采用下述三種模式來(lái)實(shí)現(xiàn)緩存策略:
1.將<%@ OutputCache Duration="60" VaryByParam="none" %>這樣的指令插入到要緩存的每個(gè)頁(yè)面中。指令指定刷新間隔(以秒為單位)。刷新間隔不依賴于外部事件,而且緩存不能全部刷新。
2.Vary-By-Parameter Caching.此模式使用Absolute Expiration的變型,該變型使開(kāi)發(fā)人員能夠指定影響頁(yè)面內(nèi)容的參數(shù)。因此,緩存將存儲(chǔ)頁(yè)面的多個(gè)版本,并按參數(shù)值為這些頁(yè)面版本編制索引。
3.Sliding Expiration Caching.此模式與Absolute Expiration(絕對(duì)過(guò)期)的類似之處是,頁(yè)面在指定的時(shí)間內(nèi)是有效的。但是,在每次請(qǐng)求時(shí)都會(huì)重置刷新間隔。例如,您可能使用滑動(dòng)過(guò)期緩存,將一個(gè)頁(yè)面緩存最長(zhǎng)10分鐘。只要對(duì)頁(yè)面的請(qǐng)求是在10分鐘內(nèi)發(fā)出的,就將過(guò)期時(shí)間再延長(zhǎng)10分鐘。

結(jié)束語(yǔ)
自此,我們已經(jīng)完整地介紹了Web表示集群中相關(guān)的各個(gè)模式,關(guān)于在MVC模式中Observer(觀察者)模式的用法,我們會(huì)用專門(mén)的篇幅來(lái)介紹,文字中提到的一些引用可以在http://www.microsoft.com/china/msdn/architecture/patterns/EspBiblio 找到相對(duì)詳細(xì)的列表,當(dāng)然,網(wǎng)絡(luò)就是您最好的資源。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多