Aspx頁面的的通常處理過程以下圖所示:html
下面經過一個更加詳細的圖形來描述aspnet_isapi.dll處理頁面的一個流程:web
請求的處理過程是基於管道模型的。編程
咱們經過下圖來理解什麼管道模型:c#
其實就是能夠有多個HttpModule,可是隻能有一個HttpHandler。api
Iis默認不會處理動態頁面,只能處理html頁面,因而就須要對iis進行擴展,這些擴展要註冊到iis中,和特定的後綴名綁定,這樣之後每當iis遇到了某個後綴名,就把他發送給響應的擴展來處理,這些篩選器處理完以後,把結果返回給iis,iis就把這個結果返回給客戶。好比對於asp,就要用asp_isapi.dll來處理,對於asp.net就要使用aspnet_isapi.dll來處理。擴展的方法有兩種:ISAPI Filter和 ISAPI Extension兩種。其中HttpModule就是篩選器;HttpHandler就是Http Extension。app
Httpmodule實現了過濾器也就是篩選器的功能;HttpModule 實現了System.Web.IHttpModule的接口。asp.net
(1) 實現步驟編程語言
l 編寫一個類,實現IHttpModule接口;ide
l 實現init方法,註冊須要的方法;函數
l 實現註冊的方法;
l 實現dispose方法,這是在爲類實現一些清除工做的時候才實現的,一般狀況下能夠什麼都不做,爲空;
l 在web.config是註冊該HttpModule類。
(2)能夠被處理的事件
其實所謂添加HttpModule,就是給HttpApplication的一些列時間添加事件處理函數,在HttpModule類中給須要添加處理函數的事件添加處理函數便可。
HttpApplication主要有如下一些事件:
l BeginRequest
l AuthenticateRequest
l AuthorizeRequest
l ResolveRequestCache
l AcquireRequestState
l PreRequestHandlerExecute
l PostRequestHandlerExecute
l ReleaseRequestState
l UpdateRequestCache
l EndRequest
全部的這些事件都可以被從新定義,可是不是override;你要明白,也就是增長了一層Module,原來的HttpModule仍然存在。這就是HttpModule的基本工做原理。
(3)一個例子
下面給出一個如何自定義HttpModule的例子。
該HttpModule名爲:MyHttpModule其中有一個AcquireRequestState事件的處理函數,整個類的定義以下:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
/// <summary>
/// Summary description for MyHttpModule
/// </summary>
public class MyHttpModule: System.Web.IHttpModule
{
public MyHttpModule()
{
//
// TODO: Add constructor logic here
//
}
public void Init(HttpApplication httpA)
{
// 向Application 對象註冊事件處理程序
httpA.AuthenticateRequest += new EventHandler(this.AuthenticateRequest);
}
public void Dispose()
{
}
private void AuthenticateRequest(object r_objSender,EventArgs r_objEventArgs)
{
HttpApplication httpA = (HttpApplication)r_objSender;
httpA.Context.Response.Write("in MyHttpModule AuthenticateRequest Event Handler");
}
}
把該類放在solution下的叫作App_Code文件夾下,而後在web.config中添加以下代碼:
<system.web>
<httpModules>
<add name="Test1" type="MyHttpModule,App_Code"/>
</httpModules>
…
</system.web>
而後給solution添加一個空白頁面,運行該頁面,獲得的結果以下:
(4)這些事件的執行順序如何?
若是想要弄清HttpApplication的全部這些事件的執行順序如何,那麼經過下面的這個例子就明白了。
咱們對上面的例子做一個簡單的修改,代碼以下:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
/// <summary>
/// Summary description for MyHttpModuleMultiEvent
/// </summary>
public class MyHttpModuleMultiEvent : System.Web.IHttpModule
{
public MyHttpModuleMultiEvent()
{
//
// TODO: Add constructor logic here
//
}
public void Init(HttpApplication httpA)
{
// 向Application 對象註冊事件處理程序
httpA.BeginRequest += new EventHandler(this.BeginRequest);
httpA.AuthenticateRequest += new EventHandler(this.AuthenticateRequest);
httpA.AuthorizeRequest += new EventHandler(this.AuthorizeRequest);
httpA.ResolveRequestCache += new EventHandler(this.ResolveRequestCache);
httpA.AcquireRequestState += new EventHandler(this.AcquireRequestState);
httpA.PreRequestHandlerExecute += new EventHandler(this.PreRequestHandlerExecute);
httpA.PostRequestHandlerExecute += new EventHandler(this.PostRequestHandlerExecute);
httpA.ReleaseRequestState += new EventHandler(this.ReleaseRequestState);
httpA.UpdateRequestCache += new EventHandler(this.UpdateRequestCache);
httpA.EndRequest += new EventHandler(this.EndRequest);
}
public void Dispose()
{
}
private void AuthenticateRequest(object r_objSender, EventArgs r_objEventArgs)
{
HttpApplication httpA = (HttpApplication)r_objSender;
httpA.Context.Response.Write("in MyHttpModule AuthenticateRequest Event Handler <br/>");
}
private void BeginRequest(object r_objSender, EventArgs r_objEventArgs)
{
HttpApplication httpA = (HttpApplication)r_objSender;
httpA.Context.Response.Write("in MyHttpModule BeginRequest Event Handler <br/>");
}
private void AuthorizeRequest(object r_objSender, EventArgs r_objEventArgs)
{
HttpApplication httpA = (HttpApplication)r_objSender;
httpA.Context.Response.Write("in MyHttpModule AuthorizeRequest Event Handler <br/>");
}
private void ResolveRequestCache(object r_objSender, EventArgs r_objEventArgs)
{
HttpApplication httpA = (HttpApplication)r_objSender;
httpA.Context.Response.Write("in MyHttpModule ResolveRequestCache Event Handler <br/>");
}
private void AcquireRequestState(object r_objSender, EventArgs r_objEventArgs)
{
HttpApplication httpA = (HttpApplication)r_objSender;
httpA.Context.Response.Write("in MyHttpModule AcquireRequestState Event Handler <br/>");
}
private void PreRequestHandlerExecute(object r_objSender, EventArgs r_objEventArgs)
{
HttpApplication httpA = (HttpApplication)r_objSender;
httpA.Context.Response.Write("in MyHttpModule PreRequestHandlerExecute Event Handler <br/>");
}
private void PostRequestHandlerExecute(object r_objSender, EventArgs r_objEventArgs)
{
HttpApplication httpA = (HttpApplication)r_objSender;
httpA.Context.Response.Write("in MyHttpModule PostRequestHandlerExecute Event Handler <br/>");
}
private void ReleaseRequestState(object r_objSender, EventArgs r_objEventArgs)
{
HttpApplication httpA = (HttpApplication)r_objSender;
httpA.Context.Response.Write("in MyHttpModule ReleaseRequestState Event Handler <br/>");
}
private void UpdateRequestCache(object r_objSender, EventArgs r_objEventArgs)
{
HttpApplication httpA = (HttpApplication)r_objSender;
httpA.Context.Response.Write("in MyHttpModule UpdateRequestCache Event Handler <br/>");
}
private void EndRequest(object r_objSender, EventArgs r_objEventArgs)
{
HttpApplication httpA = (HttpApplication)r_objSender;
httpA.Context.Response.Write("in MyHttpModule EndRequest Event Handler <br/>");
}
}
固然了,此時也要在web.config中做相應的修改;
而後運行的結果以下:
如此一來,這些事件的執行順序就一目瞭然了。
(5)配置文件中配置HttpModule的另一種方法;
另一種配置方法就是,以上面的這個例子爲例。
首先創建一個普通的工程,假設工程名爲:MyHttpModuleMultiEventProject,而後把MyHttpModuleMultiEvent.cs添加進去;編譯該工程,獲得MyHttpModuleMultiEventProject.dll,而後在要使用該httpModule的工程當中添加該dll的引用;而後在該工程的web.config中配置以下代碼:
<httpModules>
<add name ="MultiEvent" type="MyHttpModuleMultiEvent,MyHttpModuleEventProject"/>
…
</httpModules>
一切就ok了。
有一點要注意的是,在這樣配置方式下,若是想要對那些本身寫的HttpModule可以進行單步調試,就要在web.config中添加以下代碼:
<system.web>
<authorization>
<deny users="?"/>
</authorization>
…
</system.web>
否則將沒法進行調試,至於爲何,俺不明白的啦。
若是想要很好的理解一個http的執行過程,能夠參考下面的這個圖:
關鍵的一個方法是:ProcessRequest()。通常來講,只要實現這個方法就能夠了。
若是要在HttpHandler中使用Session,就必須實現IRequireSessionState。該接口指定目標HTTP處理程序接口具備對會話狀態值的讀寫訪問權限。這是一個標記接口,沒有任何方法。
本節將會在後面作一些補充
Master page 是vs2005新出來的一種頁面設計技術,它對於保持一個網站的統一風格是十分有幫助的,在以往的asp的程序中,要想讓網站保持統一的風格就只能採用ctrl+c ,ctrl +v,即便是在vs2003的時代,也仍然是採用這樣的方式。此方式最大的壞處就在於一旦風格要有所改變,那麼要改動多個地方。也就是有重複代碼的bad smell。
Master pages的好處就在於,模板只有一個,能夠被任意屢次的重複使用,並且之後若是模板須要改動,就只要修改一個地方就能夠了。
Vs2005之因此這麼作,是由於在vs2002,vs2003的使用過程當中,用戶反映到了他的許多不合理的地方,microsoft及時的對其進行了調整。
其實master page的出現是由於在vs 2005中加入了partail class技術。這種技術使得在設計期間能夠把一個class分割成多個單元,在運行的時候把這多個單元進行合併。
採用master pages 的一個好處就是,你在設計子頁的content的時候,經過vs2005的ide能夠清除的看到主頁的內容,而事實上呢,子頁的源文件並不包含master page的內容。
編輯一個master pages其實很簡單,和之前編輯任何的aspx的頁面是沒有區別的,因此在aspx頁面中可使用的控件在這裏同樣可使用。
有點稍微不一樣,也是顯而易見的就是:在master page中,你要使用一個叫作:ContentPlaceHolder的控件來標定content的區域,以便在content pages中對該區域進行編輯。
經過查看content page的源碼,你會發現他的代碼十分的簡單,下面就是一個例子:
<%@ Page Language="C#" MasterPageFile="~/MyFirstMasterPage.master" AutoEventWireup="true" CodeFile="MyFirstContentPage.aspx.cs" Inherits="MyFirstContentPage" Title="Untitled Page" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
</asp:Content>
在content page中,你只要負責編輯好content 中的內容就能夠了,其餘的什麼都不要你操心。
而在content 中編輯東西就和你之前在aspx中編輯東西是同樣的,基本感受不出有什麼不一樣。
意思就是,在master page中,你可能使用的是嵌入代碼的方式,可是這不意味你在content page當中也必定要使用嵌入代碼的方式,你徹底能夠在content page中使用界面與代碼分開的方式。
一樣的,你能夠在master page中使用vb,而後在content page中使用c#;
一切皆有可能。
能夠有三種方式:
(1) 在建立content page的時候直接指定;
(2) 在web.config中指定;
下面給出例子:
對於(2)
<configuration>
<system.web>
<pages masterPageFile=」~/Wrox.master」 />
</system.web>
</configuration>
這裏須要指出的是,採用這種方式制定的master page是整個application中共同使用的,也就是整個程序的界面風格統一,可是這並不意味着不可更改,其實你徹底能夠在某頁中修改master page。
<%@ Page Language=」VB」 MasterPageFile=」~/MyOtherCompany.master」 %>
此外,你還能夠專門爲某個目錄下的content page指定master page,代碼以下:
<configuration>
<location path=」AdministrationArea」>
<system.web>
<pages masterPageFile=」~/WroxAdmin.master」 />
</system.web>
</location>
</configuration>
(3) 在程序中經過代碼來指定;
這個其實也很簡單,代碼以下:
protected void Page_PreInit(object sender, EventArgs e)
{
MasterPageFile = "MySecondMasterPage.master";
}
注意,該屬性的修改代碼不能放在Page_Load()中,只能放在Page_PreInit()或者在這個事件以前。不要問我爲何,編譯器這麼說的。
到目前爲止,咱們給出的例子中,每一個content page都只用到一個master page。而在實際的應用中,不少組織自己就是多層的,這固然就但願master也可以有多層,如此一來組織的每一層均可以打造自身的master page。充分顯示其靈活性。
要編輯嵌套的master page有點點麻煩,主要是vs2005不可以經過view design的方式來編輯。下面說說一個二級master page的編輯過程。該例子共有三個頁面,這三個頁面之間的關係以下圖所示:mainMasterPage.master是submasterPage.master的master page, SubMasterPage.master又是ContentPage.aspx的master page。
大概步驟是這樣的:
首先創建MainMasterPage.aspx,這步和通常創建masterpage 的過程沒有什麼區別,這裏就很少說了。
代碼以下:
<%@ Master Language="C#" AutoEventWireup="true" CodeFile="MainMasterPage.master.cs" Inherits="MainMasterPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="Label1" runat="server" Text="main1"></asp:Label><br />
<asp:contentplaceholder id="ContentPlaceHolder1" runat="server">
</asp:contentplaceholder> <br />
</div>
</form>
</body>
</html>
第二步是創建SubMasterPage.master,這一步最複雜。
(1) 像創建MainMasterpage.master同樣創建一個master page,命名爲SubMasterPage.master,創建好以後代碼以下:
<%@ Master Language="C#" AutoEventWireup="true" CodeFile="SubMasterPage.master.cs" Inherits="SubMasterPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:contentplaceholder id="ContentPlaceHolder1" runat="server">
</asp:contentplaceholder>
</div>
</form>
</body>
</html>
(2) 由於創建master page的時候不能選擇繼承自哪一個master page,因此SubMasterPage.master的master page要經過手動來添加:
<%@ Master Language="C#" MasterPageFile="~/MainMasterPage.master" AutoEventWireup="true" CodeFile="subMasterPage.master.cs" Inherits="subMasterPage" %>
(3) 而後是修改SubMasterPage.master的內容,由於它是繼承自MainMasterPage.master,因此他的內容應該在mainMasterpage的content裏頭。因此其內容要修改成:
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
<asp:Label ID="Label2" runat="server" Text="main2"></asp:Label><br />
<asp:contentplaceholder id="ContentPlaceHolder2" runat="server">
</asp:contentplaceholder>
</asp:Content>
第三步是添加Contentpage.aspx,這個步驟和通常的步驟沒有區別,
可是這裏有一點要注意的是,他只能使用SubMasterPage的ContentPlaceHolder,而不能使用MainMasterPage的placeholder,代碼以下:
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder2" Runat="Server">
<asp:Label ID="Label3" runat="server" Text="content"></asp:Label><br />
</asp:Content>
整個程序運行後的結果爲: