asp.net 页面全生命周期
.Net 頁面生命周期?
2012-03-21 13:31:08|? 分類: .NET |? 標簽:.net? 頁面生命周期? c#? httpapplication? |字號大中小訂閱
.Net 頁面生命周期 IIS 所收到的對某 Microsoft ASP.NET 頁面的每個請求都被移交給 ASP.NET HTTP 管線。HTTP 管線由一系列托管對象組成,這些對象按順序處理該請求,并完成從 URL 到普通 HTML 文本的轉換。HTTP 管線的入口點是 HttpRuntime 類。ASP.NET 基礎結構為輔助進程中所承載的每個 AppDomain (應用程序域)創建此類的一個實例請注意,該輔助進程為當前正在運行的每個 ASP.NET 應用程序維護一個不同的 AppDomain。 要激活 HTTP 管道,可以創建一個 HttpRuntime 類的新實例,然后調用其 ProcessRequest 方法。一個完整的頁面請求會包括下面的流程: (1).被WWW服務器截獲(inetinfo.exe進程), 該進程首先判斷頁面后綴, 然后根據IIS中配置決定調用具體的擴展程序。aspx就會調用aspnet_isapi.dll,(2)由aspnet_isapi.dll發送給w3wp.exe(iis 工作者進程,IIS6.0中叫做 w3wq.exe,IIS5.0中叫做 aspnet_wp.exe)。 (3) 在w3wp.exe調用.NET類庫進行具體處理,順序如下:ISAPIRuntim, HttpRuntime, HttpApplicationFactory, HttpApplication, HttpModule, HttpHandlerFactory, HttpHandler ISAPIRuntime:主要作用是調用一些非托管代碼生成HttpWorkerRequest對象,HttpWorkerRequest對象包含當前請求的所有信息,然后傳遞給HttpRuntime
HttpRuntime:根據HttpWorkerRequest對象生成HttpContext,HttpContext包含request、 response等屬性, 再調用HttpApplicationFactory來生成IHttpHandler, 調用HttpApplication對象執行請求
HttpApplicationFactory: 生成一個HttpApplication對象 HttpApplication:進行HttpModule的初始化,HttpApplication創建針對此Http請求的 HttpContext對象
HttpModule: 當一個HTTP請求到達HttpModule時,整個ASP.NET Framework系統還并沒有對這個HTTP請求做任何處理,也就是說此時對于HTTP請求來講,HttpModule是一個HTTP請求的“必經之 路”,所以可以在這個HTTP請求傳遞到真正的請求處理中心(HttpHandler)之前附加一些需要的信息在這個HTTP請求信息之上,或者針對截獲 的這個HTTP請求信息作一些額外的工作,或者在某些情況下干脆終止滿足一些條件的HTTP請求,從而可以起到一個Filter過濾器的作用。
HttpHandlerFactory:把用戶request 轉發到HttpHandlerFactory,再由HttpHandlerFactory實例化HttpHandler對象來相應request HttpHandle:Http處理程序,處理頁面請求
///HttpRuntime主方法ProcessRequest(主要方法) ??? private void ProcessRequestInternal(HttpWorkerRequest wr) ??? { ??????? // 調用HttpWorkerRequest生成HttpContext ??????? HttpContext context = new HttpContext(wr, false); ??????? //傳入context,生成一個IHttpHandler實例 ??????? IHttpHandler app = HttpApplicationFactory.GetApplicationInstance(context); ??????? //調用IHttpHandler.ProcessRequest的方法 ??????? app.ProcessRequest(context); ??? } HttpApplication對象詳解 一旦請求上下文被創建,HttpRuntime類便會建立處理請求的ASP.NET應用程序對象。ASP.NET應用程序由許多 HttpApplication類的實例組成。HttpApplication是根據global.asax文件派生的對象,能夠處理轉到特定虛擬文件夾的所有HTTP請求。運行中的ASP.NET應用程序完全由其虛擬文件夾表示的,且global.asax文件是可選的。虛擬文件夾的名稱是一種鍵,HTTP運行庫通過它來確定應該由哪個應用程序來處理傳入的請求。
請求會被分配給某個HttpApplication對象,此后便由這個選定的對象來負責管理請求的整個生存期。只有在請求處理完成 后,HttpApplication對象才能被重新使用。如果沒有可用的HttpApplication對象,則將創建新的 HttpApplication對象,并被放入池中。
HttpApplication的19個標準事件 處理過程的簡單介紹 在Asp.net中,Asp.net服務器對于每一次請求的處理過程是相同的,都要經過這個HttpApplication的處理管道。管道內部的處理過程是固定的,在服務器處理請求的各個階段。伴隨著處理的進行,依次觸發對應的事件,以便于程序員在處理的各個階段完成自定義的處理工作。 開始處理請求后,第一個重要的工作就是確定請求用戶的身份以實現安全機制,這個工作通過AuthenticateRequest和PostAuthenticateRequest兩個事件提供檢查當前請求用戶身份的機會,顯然,AuthenticateRequest表示開始檢查用戶的身份,而PostAuthenticateRequest則表示用戶身份已經檢查完成,檢查后的用戶可以通過HttpContent的User屬性獲取到。這個屬性的類型為Syste.Security.Principal.IPrincipal,Iprincipal有一個名為Identity,類型為Syste.Security.Principal.IIdentity 的屬性,IIdentity有一個類型為bool型的屬性IsAuthenticated,表示當前請求的用戶是否已經被驗證,或者說確定了用戶是否是匿名用戶,IsAuthenticated如果為false,那么,表示這是一個匿名用戶,如果為true,那么通過IIdentity類型為string的Name屬性,這就是當前請求的用戶名。 ?????? 當Asp.Net獲取用戶的身份之后,根據當前請求的用戶身份,開始請求權限的檢查工作。當第4個事件AuthorizeRequest出發的時候,表示開始進行用戶的權限檢查,而第5個事件PostAuthorizeRequest則標志著已經完成了用戶權限的檢查工作。如果用戶沒有通過安全檢查,一般情況下,則跳過剩下的事件,直接觸發EndRequest事件結束請求的處理過程。 ????? 當用戶獲取了請求的權限,那么服務器開始準備用最快的方式來使用戶得到回應的結果。ResolveRequestCache事件標識著到從前緩存的結果中進行檢查,看看是否可以直接從以前緩存的結果中直接取得處理的結果,PostResolveRequestCache表示緩存檢查的結束。 ?????? 當不能從緩存中獲取結果的時候,必須通過一次處理來計算出當前請求的結果,在Asp.Net中用于處理請求以得到結果的對象成為處理程序Handler,在Asp.net中提供了許多的處理程序,程序員也可以自定義處理程序。為了處理這個請求,Asp.net必須按照匹配規則找到一個處理當前請求的處理程序,PostMapRequestHandler事件表示Asp.net已經獲取了這個處理程序,HttpContent的Handler屬性就表示這個處理程序對象,從上面的分析可以看到,HttpContent的Handler屬性到這里才有實際的意義。 ????? 得到了處理程序之后,還不能馬上開始進行處理,這是由于處理請求還需要許多與這個請求有關的數據,比如說,這個用戶在上一次向服務器發請求的時候,在服務器上保存了一些這個用戶特有的數據。從ASP時代開始,Session這個概念就出現在web開發中,提供基于回話的狀態管理,由于Http協議的無狀態性,狀態管理的問題是web開發的一個核心問題。 ????? 為了獲取這個用戶在以前保存的專屬數據,AcquireRequestStatue事件給程序員提供了一個切入點,PostAcquireRequestState事件則表示已經完成了用戶數據的獲取工作,可以在處理中使用了。 ????? 萬事俱備,只欠東風,PreRequestHandlerExecute事件用來通知程序員,處理程序就要開始進行處理工作了,如果在用戶的狀態已經獲取之后,還有需要在處理程序處理之前進行的工作,那么就在這個事件(PreRequestHandlerExecute)中處理吧 ?????? 在PreRequestHandlerExecute事件之后,asp.net服務器將通過執行處理程序完成請求的處理工作。這個處理程序可能是一個web窗體,也可能是一個web服務。這個工作在第11個事件和第12個事件之間完成。 ?????? 處理程序完成之后,服務器開始進行掃尾工作,PostRequestHandlerExecute事件通知程序員,asp.net服務器的處理程序已經完成。 ?????? 在處理完成之后,由于在處理程序中,用戶可能修改了用戶特定的專屬數據,那么,修改之后的用戶狀態數據可能需要進行序列化或者進行保存處理,ReleaseRequestState事件通知程序員需要釋放這些狀態數據,PostReleaseRequestState則表示已經釋放完成。 ?????? 在處理完成之后,如果希望將這次處理的結果緩存起來,以便于在后繼的請求中可以直接使用這個結果,UpdateRequestCache時間提供了處理的機會,PostUpdateRequestCache則表示緩存已經更新完成。HttpModule與HttpHandler區別 http://blog.csdn.net/zhaili1978/article/details/6335595
ASP.NET對請求處理的過程:
當請求一個*.aspx文件的時候,這個請求會被inetinfo.exe進程截獲,它判斷文件的后綴(aspx)之后,將這個請求轉交給ASPNET_ISAPI.dll,ASPNET_ISAPI.dll會通過http管道(Http PipeLine)將請求發送給ASPNET_WP.exe進程,在ASPNET_WP.exe進程中通過HttpRuntime來處理這個請求,處理完畢將結果返回客戶端。
inetinfo.exe進程:是www服務的進程,IIS服務和ASPNET_ISAPI.DLL都寄存在此進程中。
ASPNET_ISAPI.DLL:是處理.aspx文件的win32組件。其實IIS服務器是只能識別.html文件的,當IIS服務器發現被請求的文件是.aspx文件時,IIS服務器將其交給aspnet_isapi.dll來處理。
aspnet_wp.exe進程:ASP.NET框架進程,提供.net運行的托管環境,.net的CLR(公共語言運行時)就是寄存在此進程中。
ASP.NET Framework處理一個Http Request的流程:
HttpRequest-->inetinfo.exe-->ASPNET_ISAPI.dll-->ASPNET_WP.exe-->HttpRuntime-->HttpApplication Factory-->HttpApplication-->HttpModule-->HttpHandler Factory-->HttpHandler-->HttpHandler.ProcessRequest()
ASP.NET請求處理過程是基于管道模型的,這個管道模型是由多個HttpModule和HttpHandler組成,ASP.NET把 http請求依次傳遞給管道中各個HttpModule,最終被HttpHandler處理,處理完成后,再次經過管道中的HTTP模塊,把結果返回給客 戶端。我們可以在每個HttpModule中都可以干預請求的處理過程。
注意:在http請求的處理過程中,只能調用一個HttpHandler,但可以調用多個HttpModule。
當請求到達HttpModule的時候,系統還沒有對這個請求真正處理,但是我們可以在這個請求傳遞到處理中心(HttpHandler)之前 附加一些其它信息,或者截獲的這個請求并作一些額外的工作,也或者終止請求等。在HttpHandler處理完請求之后,我們可以再在相應的 HttpModule中把請求處理的結果進行再次加工返回客戶端。
HttpModule
HTTP模塊是實現了System.Web.IhttpModule接口的類。
IHttpModule接口的聲明:
public interface IHttpModule
{
void Init (HttpApplication context);
void Dispose ();
}
Init 方法:系統初始化的時候自動調用,這個方法允許HTTP模塊向HttpApplication 對象中的事件注冊自己的事件處理程序。
Dispose方法: 這個方法給予HTTP模塊在對象被垃圾收集之前執行清理的機會。此方法一般無需編寫代碼。
HTTP模塊可以向System.Web.HttpApplication對象注冊下面一系列事件:
AcquireRequestState 當ASP.NET運行時準備好接收當前HTTP請求的對話狀態的時候引發這個事件。
AuthenticateRequest 當ASP.NET 運行時準備驗證用戶身份的時候引發這個事件。
AuthorizeRequest 當ASP.NET運行時準備授權用戶訪問資源的時候引發這個事件。
BeginRequest 當ASP.NET運行時接收到新的HTTP請求的時候引發這個事件。
Disposed 當ASP.NET完成HTTP請求的處理過程時引發這個事件。
EndRequest 把響應內容發送到客戶端之前引發這個事件。
Error 在處理HTTP請求的過程中出現未處理異常的時候引發這個事件。
PostRequestHandlerExecute 在HTTP處理程序結束執行的時候引發這個事件。
PreRequestHandlerExecute 在ASP.NET開始執行HTTP請求的處理程序之前引發這個事件。在這個事件之后,ASP.NET 把該請求轉發給適當的HTTP處理程序。
PreSendRequestContent 在ASP.NET把響應內容發送到客戶端之前引發這個事件。這個事件允許我們在內容到達客戶端之前改變響應內容。我們可以使用這個事件給頁面輸出添加用于所有頁面的內容。例如通用菜單、頭信息或腳信息。
PreSendRequestHeaders 在ASP.NET把HTTP響應頭信息發送給客戶端之前引發這個事件。在頭信息到達客戶端之前,這個事件允許我們改變它的內容。我們可以使用這個事件在頭信息中添加cookie和自定義數據。
ReleaseRequestState 當ASP.NET結束所搜有的請求處理程序執行的時候引發這個事件。
ResolveRequestCache 我們引發這個事件來決定是否可以使用從輸出緩沖返回的內容來結束請求。這依賴于Web應用程序的輸出緩沖時怎樣設置的。
UpdateRequestCache 當ASP.NET完成了當前的HTTP請求的處理,并且輸出內容已經準備好添加給輸出緩沖的時候,引發這個事件。這依賴于Web應用程序的輸出緩沖是如何設置的。
上面這么多的事件,我們看起來可能會有些眼暈,但沒關系,下面一步一步地看。
HttpModule生命周期示意圖
下面是事件的觸發順序:
BeginRequest和PreRequestHandlerExecute之間的事件是在服務器執行HttpHandler處理之前觸發。
PostRequestHandlerExecute和PreSendRequestContent之間的事件是在服務器執行Handler處理之后觸發。
?
?
下面我們看一下如何使用HttpModule來實現我們日常的應用:
HttpModule通過在某些事件中注冊,把自己插入ASP.NET請求處理管道。當這些事件發生的時候,ASP.NET調用對相應的HTTP模塊,這樣該模塊就能處理請求了。
1、向每個頁面動態添加一些備注或說明性的文字:
有的網站每一個頁面都會彈出一個廣告或在每個頁面都以注釋形式(<!-- -->)加入網站的版權信息。如果在每個頁面教編寫這樣的JS代碼的話,對于大一點的網站,這種JS代碼的編寫與維護可是一個很繁瑣枯燥的工作。
有了HttpModule我們就可以很簡單地解決這個問題了。HttpModule是客戶端發出請求到客戶端接收到服務器響應之間的一段必經之 路。我們完全可以在服務器處理完請求之后,并在向客戶端發送響應文本之前這段時機,把這段注釋文字添加到頁面文本之后。這樣,每一個頁面請求都會被附加上 這段注釋文字。
這段代碼究竟該在哪個事件里實現呢? PostRequestHandlerExecute和PreSendRequestContent之間的任何一個事件都可以,但我比較喜歡在EndRequest事件里編寫代碼。
第一步:創建一個類庫ClassLibrary831。
第二步:編寫一個類實現IHttpModule接口
class TestModule:IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
}
}
第三步:在Init事件中注冊EndRequest事件,并實現事件處理方法
class TestModule:IHttpModule
{
public void Dispose(){}
public void Init(HttpApplication context)
{
context.EndRequest += new EventHandler(context_EndRequest);
}
void context_EndRequest(object sender, EventArgs e)
{
HttpApplication ha = (HttpApplication)sender;
ha.Response.Write("<!--這是每個頁面都會動態生成的文字。--grayworm-->");
}
}
第四步:在Web.Conofig中注冊一下這個HttpModule模塊
<httpModules>
<add name="TestModule" type="ClassLibrary831.TestModule,ClassLibrary831"></add>
</httpModules>
name:模塊名稱,一般是類名
type:有兩部分組成,前半部分是命名空間和類名組成的全名,后半部分是程序集名稱,如果類是直接放在App_Code文件夾中,那程序名稱是App_Code。
這樣在Web站點是添加該類庫的引用后,運行每個頁面,會發現其源文件中都會加入“<!--這是每個頁面都會動態生成的文字。--grayworm-->”這句話。同樣的方法你也可以在其中加入JS代碼。
2、身份檢查
大家在作登錄時,登錄成功后,一般要把用戶名放在Session中保存,在其它每一個頁面的Page_Load事件中都檢查Session中是否存在用戶名,如果不存在就說明用戶未登錄,就不讓其訪問其中的內容。
在比較大的程序中,這種做法實在是太笨拙,因為你幾乎要在每一個頁面中都加入檢測Session的代碼,導致難以開發和維護。下面我們看看如何使用HttpModule來減少我們的工作量
由于在這里我們要用到Session中的內容,我們只能在AcquireRequestState和 PreRequestHandlerExecute事件中編寫代碼,因為在HttpModule中只有這兩事件中可以訪問Session。這里我們選擇 PreRequestHandlerExecute事件編寫代碼。
第一步:創建一個類庫ClassLibrary831。
第二步:編寫一個類實現IHttpModule接口
class TestModule:IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
}
}
第三步:在Init事件中注冊PreRequestHandlerExecute事件,并實現事件處理方法
class AuthenticModule:IHttpModule
{
public void Dispose(){}
public void Init(HttpApplication context)
{
context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
}
void context_PreRequestHandlerExecute(object sender, EventArgs e)
{
HttpApplication ha = (HttpApplication)sender;
string path = ha.Context.Request.Url.ToString();
int n = path.ToLower().IndexOf("Login.aspx");
if (n == -1) //是否是登錄頁面,不是登錄頁面的話則進入{}
{
if (ha.Context.Session["user"] == null) //是否Session中有用戶名,若是空的話,轉向登錄頁。
{
ha.Context.Response.Redirect("Login.aspx?source=" + path);
}
}
}
}
?
?
第四步:在Login.aspx頁面的“登錄”按鈕中加入下面代碼
protected void Button1_Click(object sender, EventArgs e)
{
if(true)??? //判斷用戶名密碼是否正確
{
if (Request.QueryString["source"] != null)
{
string s = Request.QueryString["source"].ToLower().ToString();?? //取出從哪個頁面轉來的
Session["user"] = txtUID.Text;
Response.Redirect(s); //轉到用戶想去的頁面
}
else
{
Response.Redirect("main.aspx");??? //默認轉向main.aspx
}
}
}
第五步:在Web.Conofig中注冊一下這個HttpModule模塊
<httpModules>
<add name="TestModule" type="ClassLibrary831.TestModule,ClassLibrary831"></add>
</httpModules>
3、多模塊的操作
如果定義了多個HttpModule,在web.config文件中引入自定義HttpModule的順序就決定了多個自定義HttpModule在處理一個HTTP請求的接管順序。
HttpHandler
HttpHandler是HTTP請求的處理中心,真正地對客戶端請求的服務器頁面做出編譯和執行,并將處理過后的信息附加在HTTP請求信息流中再次返回到HttpModule中。
HttpHandler與HttpModule不同,一旦定義了自己的HttpHandler類,那么它對系統的HttpHandler的關系將是“覆蓋”關系。
IHttpHandler接口聲明
public interface IHttpHandler
{
bool IsReusable { get; }
public void ProcessRequest(HttpContext context); //請求處理函數
}
示例:把硬盤上的圖片以流的方式寫在頁面上
class TestHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
FileStream fs = new FileStream(context.Server.MapPath("worm.jpg"), FileMode.Open);
byte[] b = new byte[fs.Length];
fs.Read(b, 0, (int)fs.Length);
fs.Close();
context.Response.OutputStream.Write(b, 0, b.Length);
}
public bool IsReusable
{
get
{
return true;
}
}
}
Web.Config配置文件
<httpHandlers>
<add verb="*" path="*" type="ClassLibrary831.TestHandler,ClassLibrary831"></add>
</httpHandlers>
Verb屬性:指定了處理程序支持的HTTP動作。*-支持所有的HTTP動作;“GET”-支持Get操作;“POST”-支持Post操作;“GET, POST”-支持兩種操作。
Path屬性:指定了需要調用處理程序的路徑和文件名(可以包含通配符)。“*”、“*.aspx”、“showImage.aspx”、“test1.aspx,test2.aspx”
Type屬性:用名字空間、類名稱和程序集名稱的組合形式指定處理程序或處理程序工廠的實際類型。ASP.NET運行時首先搜索bin目錄中的DLL,接著在GAC中搜索。
這樣程序運行的效果是該網站的任何一個頁面都會顯示worm.jpg圖片。如何只讓一個頁面(default21.aspx)執行 HttpHandler中的ProcessRequest方法呢?最簡單的辦法是在Web.Config文件中把path配置信息設為 default21.aspx。
?
?
根據這個例子大家可以考慮一下如何編寫“驗證碼”了。
IHttpHandler工廠
IHttpHandlerFactory的作用是對IHttpHandler進行管理。工廠的作用請見http://hi.baidu.com/grayworm/blog/item/4a832160f8c9de46eaf8f8c1.html"
IHttpHandlerFactory接口的聲明:
public interface IHttpHandlerFactory
{
IHttpHandler GetHandler (HttpContext context,string requestType,string url,string pathTranslated);
void ReleaseHandler (IHttpHandler handler);
}
GetHandler返回實現IHttpHandler接口的類的實例,ReleaseHandler使工廠可以重用現有的處理程序實例。
示例:兩個用IHttpHandlerFactory來實現對不同HttpHandler的調用。
有兩個HttpHandler:將圖片顯示在頁面上的HttpHandler和生成驗證碼的Handler
//將圖片顯示在頁面上的Handler
class TestHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
FileStream fs = new FileStream(context.Server.MapPath("worm.jpg"), FileMode.Open);
byte[] b = new byte[fs.Length];
fs.Read(b, 0, (int)fs.Length);
fs.Close();
context.Response.OutputStream.Write(b, 0, b.Length);
}
public bool IsReusable
{
get
{
return true;
}
}
}
//生成驗證碼的Handler
class CodeHandler:IHttpHandler
{
public bool IsReusable
{
get
{
return true;
}
}
public void ProcessRequest(HttpContext context)
{
Image b = new Bitmap(50,20);
Graphics g = Graphics.FromImage(b);
SolidBrush sb = new SolidBrush(Color.White);
Font f = new Font("宋體", 12);
string str = "";
Random r = new Random();
for (int i = 0; i < 4; i++)
{
str += r.Next(10);
}
g.DrawString(str,f,sb,0,0);
b.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
IHttpHandler工廠
class TestHandlerFactory : IHttpHandlerFactory
{
public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
{
string fname = url.Substring(url.IndexOf('/') + 1);
while (fname.IndexOf('/') != -1)
fname = fname.Substring(fname.IndexOf('/') + 1);
string cname = fname.Substring(0, fname.IndexOf('.'));
string className ="";
className = "ClassLibrary831.CodeHandler";
object h = null;
try
{
//h = new TestHandler();
h = Activator.CreateInstance(Type.GetType(className));
}
catch (Exception e)
{
throw new HttpException("工廠不能為類型" + cname + "創建實例。", e);
}
return (IHttpHandler)h;
}
public void ReleaseHandler(IHttpHandler handler)
{
}
}(車延祿)
配置文件
<httpHandlers>
<add verb="*" path="default21.aspx,default22.aspx" type="ClassLibrary831.TestHandlerFactory,ClassLibrary831"></add>
</httpHandlers>
這樣TestHandlerFactory就會根據請求的不同頁面執行不同的HttpHandler處理程序了。
?
?
?
HttpHandler使用會話
如果要在處理程序中使用Session,那必須把該HttpHandler實現IRequiresSessionState接口,,IRequiresSessionState接口是個空接口,它沒有抽象方法,只是一個標記。此處就不作例子驗證了
ASP.Net處理Http Request時,使用Pipeline(管道)方式,由各個HttpModule對請求進行處理,然后到達 HttpHandler,HttpHandler處理完之后,仍經過Pipeline中各個HttpModule的處理,最后將HTML發送到客戶端瀏覽 器中。
生命周期中涉及到幾個非常重要的對象:HttpHandler,HttpModule,IHttpHandlerFactory,他們的執行(順序)大致的執行過程是這樣的:client端發送頁面請求,被IIS的某個進程截獲,它根據申請的頁 面后綴(.aspx)不同,調用不同的頁面處理程序(.asp->asp.dll; .aspx->ISAPI.dll).而頁面處理程序在處理過程中,則要經歷HttpModule,HttpHandler的處理:前者HttpModule用于頁面處理前和處理后的一些事件的處理,后者HttpHandler進行真正的頁面的處理。
如前所說,HttpModule會在頁面處理前和后對頁面進行處理,所以它不會影響真正的頁面請求。通常用在給每個頁面的頭部或者尾部添加一些信息(如版 權聲明)等.曾經見過一些免費的空間,我們的頁面上傳上去后,瀏覽的時候發現,在每個頁面的頭部和尾部多了很多小廣告....,如果理解了 HttpModule的原理,要做這個就不是很難了~
IHttpModule與IHttpHandler的區別整理
1.先后次序.先IHttpModule,后IHttpHandler. 注:Module要看你響應了哪個事件,一些事件是在Handler之前運行的,一些是在Handler之后運行的
2.對請求的處理上:
IHttpModule是屬于大小通吃類型,無論客戶端請求的是什么文件,都會調用到它;例如aspx,rar,html的請求.
IHttpHandler則屬于挑食類型,只有ASP.net注冊過的文件類型(例如aspx,asmx等等)才會輪到調用它.
3.IHttpHandler按照你的請求 生成響應的內容,IHttpModule對請求進行預處理,如驗證、修改、過濾等等,同時也可以對響應進行處理
ASP.Net系統本身配置有很多HttpHandler和HttpModule,以處理aspx等.Net標準的頁面文件,以及這些頁面文件中標 準的事件處理等。查看%System%/Microsoft.NET/Framework/v2.0.50727/CONFIG目錄下的 web.config文件中的httpHandlers和httpModules節點,可以看到這些配置。如果有興趣,可以使用Reflector查 看.Net系統中相關的類和方法,了解.Net如何處理以及做了什么處理。
.Net也提供了一套機制來開發自定義的HttpHandler和 HttpModule,均可以用于對HttpRequest的截取,完成自定義的處理。 HttpModule 繼承System.Web.IHttpModule接口,實現自己的HttpModule類。必須要實現接口的兩個方法:Init和Dispose。在 Init中,可以添加需要截取的事件;Dispose用于資源的釋放,如果在Init中創建了自己的資源對象,請在Dispose中進行釋放。
namespace MyModule
{
public class MyHttpModule : IHttpModule
{
public MyHttpModule()
{
}
//Init方法用來注冊HttpApplication 事件。
public void Init(HttpApplication r_objApplication)
{
r_objApplication.BeginRequest += new EventHandler(this.BeginRequest);
}
public void Dispose()
{
}
private void BeginRequest(object r_objSender, EventArgs r_objEventArgs)
{
HttpApplication objApp = (HttpApplication)r_objSender;
objApp.Response.Write("您請求的URL為" + objApp.Request.Path);
}
}
}
將編譯的dll文件拷貝到web項目的bin目錄下,在web項目的web.config文件system.web節點中配置:
這樣就將自定義的HttpModule類MyHttpModule插入到了當前web的HttpModule的Pipeline中。 HttpModule主要功能是對Application的各個事件進行截取,在這些事件中完成自己的處理。其實如果自己開發一些項目,直接在 Global.asax中處理已經足夠了。如果是開發一個Framework或者是某些方面的組件,需要在事件中添加處理,開發自定義的 HttpModule,可以避免使用Framework或者組件時,還得手工在Global.asax中添加代碼。???? 目前想到的開發自定義HttpModule的用途,有全局的身份/權限驗證、自定義網站訪問/操作日志的記錄、處于管理/調試等目的對站點進行監控追蹤 等。當然,如果是結合自定義的HttpHandler進行Framework的開發,HttpModule可以用于其它的一些特殊的處理。
<httpModules>
<add name="test" type="MyHttpModuleTest.MyHttpModule,MyHttpModule"/>
</httpModules>
注意要區分大小寫,因為web.config作為一個XML文件是大小寫敏感的。“type=MyHttpModuleTest.MyHttpModule,MyHttpModule”告訴我們
系統將會將http request請求交給位于MyHttpModule.dll文件中的MyHttpModuleTest.MyHttpModule類去處理。
HttpHandler是完全的對Http Request的截取。
首先,繼承System.Web.IHttpHandler接口,實現自己的HttpHandler類。必須要實現接口的ProcessRequest方 法和IsReusable屬性。ProcessRequest方法中完成對每個Http Request的處理,發送處理結果的HTML到輸出緩存中。IsReusable屬性被.Net Framework調用,用以確定這個HttpHandler的實例是否可以被重用于同類型其它的Request處理。
如果你在自己的HttpHandler類中,需要讀取或者是寫Session值,需要再繼承一個接口IRequiresSessionState。這個接 口沒有任何方法,只是一個標記接口。繼承這個接口之后,就可以在自己的HttpHandler中訪問Session,可以在Session中寫入值。
namespace MyHandler
{
public class MyHttpHandler : IHttpHandler, IRequiresSessionState
{
public MyHttpHandler() {}
public bool IsReusable
{
get { return true; }
}
?
?
?
public void ProcessRequest(HttpContext context)
{
HttpResponse objResponse = context.Response ;
objResponse.Write("
This request is handled by MyHttpHandler
");
}
}
}
把編譯的dll文件拷貝到web項目的bin目錄下。
接下來,這樣來測試一下MyHttpHandler。我們為IIS配置一個以.cc為后綴名的文件類型,用我們寫的MyHttpHandler來處理。
首先,在IIS站點的Configuration配置里面,添加一個對.cc后綴名處理的Application Extention Mapping項。
然后,在web項目的web.config節點節點中配置:
MyHttpHandler, MyHandler"/>
verb屬性配置這個HttpHandler處理那些HTTP方法,例如GET、POST等,如果是處理所有方法,就用*。path屬性配置HttpHandler對哪些文件進行處理,例如可以是myfile.cc,如果是處理所有的.cc文件,就用*.cc。
這樣,這個站點上所有.cc類型文件的訪問,都由MyHttpHandler處理。使用http://localhost/站點虛擬目錄/a.cc訪問測試站點,可以看到測試效果。當然,a.cc這個文件在Web服務器上是并不存在的。
對HttpHandler的使用,比較典型的有.Net的Web MVC開源項目Maverick。Maverick使用一個Dispatcher類對所有的Http Request進行截取,他以.m作為后綴名向Web服務器提交請求,在Dispatcher中,將.m的后綴去掉,提取Command Name,然后以這個command name從配置文件中加載處理的flow,形成一個chain,依次對chain上的各個command和view進行處理,對各個command和 view的處理結果可能會在chain中選擇不同的處理分支,每個處理的Step中將處理結果的HTML寫入Response的緩存中進行輸出。
總體來說,Maverick的框架架構概念很不錯,但也存在明顯的缺陷,以后有時間再詳細的寫寫它的架構和需要改進之處。
總之,將HttpModule、HttpHandler,以及使用Ajax等將客戶端進行封裝結合起來,能夠給web項目的開發帶來非常大的改善空間。
Asp.Net HttpHandler實現URL重寫的
我們經常看到很多網站訪問文章的時候才用的是***.html 或***.shtml (如本blog的日志訪問效果),其時這寫文件在服務器上不存在的,那為什么會出現這樣的效果呢,是因為Web服務器上對URL執行了重寫,把訪問的 URL根據特定的格式重寫成內部訪問頁面來實現的,它的好處是便于用戶理解,同時搜索引擎也能更好地收入你的網站,當然其它的好處也很多,這里不做一一介 紹了。
本文所講的是使用Asp.Net中的HttpHandler實現URL重寫的,它所實現的原理請看這里,本程序可以處理任何Url,因為我在程序中使用了URL過慮,只有訪問文件名是數字的才進行處理,并指在內部執行一個新的頁面,并輸出數據,代碼如下:
public void ProcessRequest(HttpContext Context)
{
try {
//申明Request
HttpRequest Request = Context.Request;
//取來路Url的絕對路徑
string Url = Request.Url.AbsolutePath;
//取訪問的Web文件的開始字符間隔數
int RegStart = Url.LastIndexOf("/") + 1;
//申明一個確定Web文件名是否全是數字
Regex Reg = new Regex(@"/d+");
//用正則表達式進行匹配
if (Reg.IsMatch(Url, RegStart))
{
// 如果web文件名是數字,則判定是查詢相關文章,執行指定頁面???????????? Context.Server.Execute("~/PermaLink.aspx?id=" + Reg.Match(Url, RegStart).Value);
}
}
catch
{
Context.Response.Redirect(Context.Request.Url.ToString());
}
}
當然你首先要做的是先建一個類,并繼承自IHttpHandler,然后把這段代碼拷入,并編譯。在Web項目中若要使用此功能,需要在web.config里面加上如下語句:
<httpHandlers>
<add verb="*" path="*.shtml" type="HttpHandle.UrlRewrite" />
</httpHandlers>
同時,還要在IIS中對Web項目進行配置,在Web項目的屬性中,在主目錄選項卡里,把執行權限改為"腳本和可執行文件",然后打開配置,在應用程序擴展里加上需重寫的文件格式的擴展,好了,成事具備,只欠運行了。
轉載于:https://www.cnblogs.com/wuyanbin/p/3200553.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的asp.net 页面全生命周期的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 20130717随想
- 下一篇: iOS toolchain based