天天看點

HttpHandler與HttpModule講解

實作HttpHandler

HttpHandler對象必須實作IHttpHandler接口,在HttpApplication對象轉交要求至HttpHandler對象時會調用此接口中的init函數,下面是一個HelloHandler類的程式。

using System;
using System.Web;
using System.Web.SessionState;

namespace c64.HttpHandler
{
	public class HelloHandler : IHttpHandler,IRequiresSessionState
	{		
		#region IHttpHandler Members

		public void ProcessRequest(HttpContext context)
		{
			context.Response.ContentType = "text/html";
			context.Response.Write("<html>");
			context.Response.Write("<body>");
			context.Response.Write("<B>Response By HelloHandler</B>");
			context.Response.Write("</body");
			context.Response.Write("</html>");
		}

		public bool IsReusable
		{
			get
			{				
				return true;
			}
		}

		#endregion
	}
}
           

挂載這個HttpHandler對象的方法有兩種,一種是直接修改.NET Framework目錄中的machine.config檔案,這樣做将本機上所有的asp.net程式挂載此HttpHandler對象,另一中方式是修改虛拟目錄中的web.config檔案,此方案隻會影響該虛拟目錄中的asp.net程式。此處采用第二種方式,請于web.config檔案中加入下面的叙述。

<httpHandlers>

   <add verb="*" path=".ho" type="c64.HttpHandler.HelloHandler,HelloHanlder"/>

</httpHanlders>

path部分的設定是告知HttpApplication對象此HttpHandler對象時對應那一種檔案擴充名,type設定的前段是類的名稱與namespace,後段是Assembly檔案名。除此之外,要讓aspnet_isapi.dll接受.ho檔案的要求,還得在IIS中設定虛拟目錄的内容設定擴充名對應表。

HttpHandler與HttpModule講解

關于Session

預設情況下,當HttpHandler對象被調用時Session對象并未初始化成可用狀态,倘若HttpHandler對象須要使用到Session對象時,必須同時實作IRequiresSessionState接口,此接口隻是識别用途,無須實作任何的方法,下面的程式實作了IRequiresSessionState接口的HelloHandler類源代碼。

using System;
using System.Web;
using System.Web.SessionState;

namespace c64.HttpHandler
{
	public class HelloHandler : IHttpHandler,IRequiresSessionState
	{		
		#region IHttpHandler Members

		public void ProcessRequest(HttpContext context)
		{
			context.Response.ContentType = "text/html";
			context.Response.Write("<html>");
			context.Response.Write("<body>");
			context.Response.Write("<B>Response By HelloHandler</B>");
			string user = (string)context.Session["USER"];
			if(user != null && user.Length > 0)
                context.Response.Write(user);
			context.Response.Write("</body");
			context.Response.Write("</html>");
		}

		public bool IsReusable
		{
			get
			{				
				return true;
			}
		}

		#endregion
	}
}
           

要測試這個程式,我們可以在WebForm上放置一個按鈕,當使用者按下後存放一個字元串到Session["USER"]中,接着要求.ho的檔案就可以看到結果。

實作HttpModule

與HttpHandler對象的加載時機不同,HttpModule對象是在HttpApplication對象初始化時就一并載入的,這個時機是在本機開機後第一個使用者通路此虛拟目錄時。設計人員撰寫HttpModule對象的機會不多,甚至比撰寫HttpHandler對象的機會還少。下面撰寫一個HelloModule對象來示範如何撰寫HttpModule對象。

using System;
using System.Web;
using System.Web.SessionState;

namespace HttpModule
{
	public class HelloModule : IHttpModule,IRequiresSessionState
	{		
		#region IHttpModule Members

		public void Init(HttpApplication context)
		{
			context.Application["HELLO"] = "I am Hello Module!";
			context.Application[GetHashCode().ToString()] = 123;
		}

		public void Dispose()
		{			
		}

		#endregion
	}
}
           

這個HelloModule對象隻是很簡單地在Application的State對象中放入一個字元串,與加載HttpHandler對象的方式相同,我們可以修改mechine.config檔案或是虛拟目錄内的web.config檔案來載入它,此處采用第二種方案,請于web.config檔案中放入以下的叙述。

<httpModules>

   <add name ="HelloModule"  type="HttpModule.HttpModule,HelloModule"/>

</httpModules>

要測試這個HelloModule對象,隻須與WebForm上放置一個按鈕,當使用者按下後由Application State對象中取出由HelloModule對象所放入的字元串即可,下圖是HelloModule對象的執行結果。

IHttpModule實作權限控制

總所周知實作一個系統權限管理子產品有很多種實作方式,在這裡和大家探讨下管道模型實作權限管理子產品。

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中進行判斷,如果不是指定角色,就拒絕其通路

先了解下IHttpModule這個接口:

   IHttpModule向實作類提供子產品初始化和處置事件。

IHttpModule包含兩個方法:

public void Init(HttpApplication context);

public void Dispose();

Init():這個方法接受一個HttpApplication對象,HttpApplication代表了目前的應用程式,我們需要在這個方法内注冊 HttpApplication對象暴露給用戶端的事件。可見,這個方法僅僅是用來對事件進行注冊,而實際的事件處理程式,需要我們另外寫方法。

整個過程很好了解:

1.       當站點第一個資源被通路的時候,Asp.Net會建立HttpApplication類的執行個體,它代表着站點應用程式,同時會建立所有在Web.Config中注冊過的Module執行個體。

2.       在建立Module執行個體的時候會調用Modul的Init()方法。

3.       在Init()方法内,對想要作出響應的HttpApplication暴露出的事件進行注冊。(僅僅進行方法的簡單注冊,實際的方法需要另寫)。

4.       HttpApplication在其應用程式周期中觸發各類事件。

5.       觸發事件的時候調用Module在其Init()方法中注冊過的方法。

Dispose():它可以在進行垃圾回收之前進行一些清理工作。

實作步驟:

先建立一個登陸頁面Login.aspx;主要代碼:

 protected void btnLogin_Click(object sender, EventArgs e)

        {

         if (this.txtUserName.Text.Trim()!="" && this.txtPwd.Text.Trim()!="")

          {

            string url = Request.QueryString["ReturnUrl"];

            //添加身份驗證票證

            FormsAuthentication.RedirectFromLoginPage(this.txtUserName.Text, false);

            if (url!=null)

            {

                Response.Redirect(url);

            }

            Response.Redirect("Index.aspx");

        }

    }

建立一個類實作IHttpModule接口:Test.cs

using System;

 using System.Collections.Generic;

 using System.Linq;

 using System.Web;

/// <summary>

///Test 的摘要說明

/// </summary>

public class Test:IHttpModule

{

 public Test()

 {

  //

  //TODO: 在此處添加構造函數邏輯

  //

 }

    #region IHttpModule 成員

 public void Dispose()

        {

           //throw new NotImplementedException();

        }

 public void Init(HttpApplication context)

       {

        // 注冊HttpApplication應用程式 AcquireRequestState 事件

        context.AcquireRequestState += new EventHandler(context_AcquireRequestState);

        }

 void context_AcquireRequestState(object sender, EventArgs e)

        {

             HttpApplication app =(HttpApplication) sender;

             //擷取目前請求的路徑

            string path = app.Context.Request.Path;

            //判斷是不是登陸頁面

             if (!path.EndsWith("login.aspx"))

               {   //判斷目前登入使用者是不是admin

                  if (app.Context.User.Identity.Name!="admin")

                   {   //如果登入使用者不是admin就無權檢視目前頁面,重定向錯誤頁面

                      app.Context.Server.Transfer("Error.aspx?message=" + path + "");

                   }

         }

         //throw new NotImplementedException();

    }

    #endregion

}

 http://xiaolongwang168.blog.163.com/blog/static/123642111201173095828628/