关于HttpModule的注册、应用方法请参看我的另一篇博文:
关于IHttpHandler的应用,我们先从它的注册方法讲起。
当你建立了一个实现了Ihttphandler接口的类后,可以在网站的web.config文件中注册这个httphandler
示例如下:
< 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"/>
便是我们手工加入的内容,WebApplication2.HelloHandler是实现了IhttpHandler接口的一个类,Path属性表示的是映射的文件格式。
这样注册好之后,如果从网站请求任何带后缀名.ho的文件时,就会转到WebApplication2.HelloHandler类进行处理。
而WebApplication2.HelloHandler的内容可以是在网页上打印一行文本(如下面代码),也可以是下载一个文件,反正在httphandler里面你可以控制response对象的输出。
下面代码示例打印一行文字的WebApplication2.HelloHandler源码:
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
}
}
以下内容为转载的IhttpHandler示例:利用IhttpHandler实现文件下载
1. 首先新建一个用于下载文件的page页,如download.aspx,里面什么东西也没有。
2. 添加一个DownloadHandler类,它继承于IHttpHandler接口,可以用来自定义HTTP 处理程序同步处理HTTP的请求。
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. 这里涉及到一个文件名加解密的问题,是为了防止文件具体名称暴露在状态栏中,所以添加一个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码对文件名进行加解密处理。
4. 在Web.config上,添加httpHandlers结点,如下:
<httpHandlers>
<add verb="*" path="download.aspx" type="DownloadHandler" />
</httpHandlers>
</system.web>
5. 现在新建一个aspx页面,对文件进行下载:
Default.aspx代码如下:
<%@ 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.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;
}
}
这样就实现了文件下载时,不管是什么格式的文件,都能够弹出打开/保存窗口。