ASP.NET 提供了 IHttpHandler 和 IHttpModule 接口,它可使您使用與在 IIS 中所用的 Internet 服務(wù)器 API (ISAPI) 編程接口同樣強(qiáng)大的 API,而且具有更簡單的編程模型。HTTP 處理程序?qū)ο笈c IIS ISAPI 擴(kuò)展的功能相似,而 HTTP 模塊對象與 IIS ISAPI 篩選器的功能相似。
ASP.NET 將 HTTP 請求映射到 HTTP 處理程序上。每個(gè) HTTP 處理程序都會(huì)啟用應(yīng)用程序內(nèi)單個(gè)的 HTTP URL 處理或 URL 擴(kuò)展組處理。HTTP 處理程序具有和 ISAPI 擴(kuò)展相同的功能,同時(shí)具有更簡單的編程模型。
HTTP 模塊是處理事件的程序集。ASP.NET 包括應(yīng)用程序可使用的一組 HTTP 模塊。例如,ASP.NET 提供的 SessionStateModule 向應(yīng)用程序提供會(huì)話狀態(tài)服務(wù)。也可以創(chuàng)建自定義的 HTTP 模塊以響應(yīng) ASP.NET 事件或用戶事件。
關(guān)于HttpModule的注冊、應(yīng)用方法請參看我的另一篇博文:
使用HTTP模塊擴(kuò)展 ASP.NET 處理
關(guān)于IHttpHandler的應(yīng)用,我們先從它的注冊方法講起。
當(dāng)你建立了一個(gè)實(shí)現(xiàn)了Ihttphandler接口的類后,可以在網(wǎng)站的web.config文件中注冊這個(gè)httphandler
示例如下:
<httpHandlers>
<remove verb="*" path="*.asmx"/>
<add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add verb="*" path="*.ho" type="WebApplication2.HelloHandler,WebApplication2"/>
</httpHandlers>
其中最后一行 <add verb="*" path="*.ho" type="WebApplication2.HelloHandler,WebApplication2"/>
便是我們手工加入的內(nèi)容,WebApplication2.HelloHandler是實(shí)現(xiàn)了IhttpHandler接口的一個(gè)類,Path屬性表示的是映射的文件格式。
這樣注冊好之后,如果從網(wǎng)站請求任何帶后綴名.ho的文件時(shí),就會(huì)轉(zhuǎn)到WebApplication2.HelloHandler類進(jìn)行處理。
而WebApplication2.HelloHandler的內(nèi)容可以是在網(wǎng)頁上打印一行文本(如下面代碼),也可以是下載一個(gè)文件,反正在httphandler里面你可以控制response對象的輸出。
下面代碼示例打印一行文字的WebApplication2.HelloHandler源碼:
using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
namespace WebApplication2
{
public class HelloHandler:IHttpHandler
{
#region IHttpHandler
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
}
}
以下內(nèi)容為轉(zhuǎn)載的IhttpHandler示例:利用IhttpHandler實(shí)現(xiàn)文件下載
1. 首先新建一個(gè)用于下載文件的page頁,如download.aspx,里面什么東西也沒有。
2. 添加一個(gè)DownloadHandler類,它繼承于IHttpHandler接口,可以用來自定義HTTP 處理程序同步處理HTTP的請求。
using System.Web;
using System;
using System.IO;
public class DownloadHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
HttpResponse Response = context.Response;
HttpRequest Request = context.Request;
System.IO.Stream iStream = null;
byte[] buffer = new Byte[10240];
int length;
long dataToRead;
try
{
string filename = FileHelper.Decrypt(Request["fn"]); //通過解密得到文件名
string filepath = HttpContext.Current.Server.MapPath("~/") + "files/" + filename; //待下載的文件路徑
iStream = new System.IO.FileStream(filepath, System.IO.FileMode.Open,
System.IO.FileAccess.Read, System.IO.FileShare.Read);
Response.Clear();
dataToRead = iStream.Length;
long p = 0;
if (Request.Headers["Range"] != null)
{
Response.StatusCode = 206;
p = long.Parse(Request.Headers["Range"].Replace("bytes=", "").Replace("-", ""));
}
if (p != 0)
{
Response.AddHeader("Content-Range", "bytes " + p.ToString() + "-" + ((long) (dataToRead - 1)).ToString() + "/" + dataToRead.ToString());
}
Response.AddHeader("Content-Length", ((long) (dataToRead - p)).ToString());
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment; filename=" + System.Web.HttpUtility.UrlEncode(System.Text.Encoding.GetEncoding(65001).GetBytes(Path.GetFileName(filename))));
iStream.Position = p;
dataToRead = dataToRead - p;
while (dataToRead > 0)
{
if (Response.IsClientConnected)
{
length = iStream.Read(buffer, 0, 10240);
Response.OutputStream.Write(buffer, 0, length);
Response.Flush();
buffer = new Byte[10240];
dataToRead = dataToRead - length;
}
else
{
dataToRead = -1;
}
}
}
catch (Exception ex)
{
Response.Write("Error : " + ex.Message);
}
finally
{
if (iStream != null)
{
iStream.Close();
}
Response.End();
}
}
public bool IsReusable
{
get { return true; }
}
}
3. 這里涉及到一個(gè)文件名加解密的問題,是為了防止文件具體名稱暴露在狀態(tài)欄中,所以添加一個(gè)FileHelper類,代碼如下:
public class FileHelper
{
public static string Encrypt(string filename)
{
byte[] buffer = HttpContext.Current.Request.ContentEncoding.GetBytes(filename);
return HttpUtility.UrlEncode(Convert.ToBase64String(buffer));
}
public static string Decrypt(string encryptfilename)
{
byte[] buffer = Convert.FromBase64String(encryptfilename);
return HttpContext.Current.Request.ContentEncoding.GetString(buffer);
}
}
利用Base64碼對文件名進(jìn)行加解密處理。
4. 在Web.config上,添加httpHandlers結(jié)點(diǎn),如下:
<system.web>
<httpHandlers>
<add verb="*" path="download.aspx" type="DownloadHandler" />
</httpHandlers>
</system.web>
5. 現(xiàn)在新建一個(gè)aspx頁面,對文件進(jìn)行下載:
Default.aspx代碼如下:
Code
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!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>文件下載</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:HyperLink ID="link" runat="server" Text="文件下載"></asp:HyperLink>
</div>
</form>
</body>
</html>
Default.aspx.cs代碼如下:
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;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string url = FileHelper.Encrypt("DesignPattern.chm");
link.NavigateUrl = "~/download.aspx?fn=" + url;
}
}
這樣就實(shí)現(xiàn)了文件下載時(shí),不管是什么格式的文件,都能夠彈出打開/保存窗口。