ASP.NET基础之HttpHandler学习

经过前两篇[ASP.NET基础之HttpModule学习]和[ASP.NET基础之HttpContext学习]文章的学习我们对ASP.NET的基础内容有一个比较详细的了解,本文将对第三个比较重要的知识HttpHandler进行学习,将通过一些理论跟实例来演示HttpHandler运用;有部分理论知识来源于网源,希望对您的阅读有所帮助;

一:HttpHandler理论知识

1:IHttpHandler定义了如果要实现一个HTTP请求的处理所必需实现的一些系统约定。HttpHandler与HttpModule不同,一旦定义了自己的HttpHandler类,那么它对系统的HttpHandler的关系将是“覆盖”关系。

2:当一个HTTP请求经同HttpModule容器传递到HttpHandler容器中时,ASP.NET Framework会调用HttpHandler的ProcessRequest成员方法来对这个HTTP请求进行真正的处理。以一个ASPX页面为例,正是在这里一个ASPX页面才被系统处理解析,并将处理完成的结果继续经由HttpModule传递下去,直至到达客户端。对于ASPX页面,ASP.NET Framework在默认情况下是交给System.Web.UI.PageHandlerFactory这个HttpHandlerFactory来处理的。HttpHandlerFactory;HttpHandlerFactory,是指当一个HTTP请求到达这个HttpHandler Factory时,HttpHandlerFactory会提供出一个HttpHandler容器,交由这个HttpHandler容器来处理这个HTTP请求。针对.aspx在machine.config中是这样定义的:

<add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory"/> 

3:一个HTTP请求都是最终交给一个HttpHandler容器中的ProcessRequest方法来处理的。

4:其实我们可以自定义HttpHandler来处理某些特殊文件的请求或者逻辑的实现;自定义HttpHandler必须实现接口IHttpHandler;其中属性IsReusable表示获取一个值,该值指示其他请求是否可以使用 IHttpHandler 实例。而方法ProcessRequest则是以一个HttpContext的上下文为参数;这些我们就可以操作HttpContext里封装的Request,Response,Server等;

 

二:HttpHandler之一般程序处理类(Handler.ashx)

1:在我们讲解自定义HttpHandler时,我们首先看下VS里的一般程序处理类(Handler.ashx),在我们平常开发过程中其实已经有应用到一些HttpHandler,比如我们新建一个一般程序处理类时

<%@ WebHandler Language="C#" Class="Handler" %>

using System;
using System.Web;

public class Handler : IHttpHandler {
    
    public void ProcessRequest (HttpContext context) {
        context.Response.ContentType = "text/plain";
        context.Response.Write("Hello World");
    }
 
    public bool IsReusable {
        get {
            return false;
        }
    }

}

上面的代码是增加完一个一般处理程序系统默认为我们增加的内容;以前对HttpHandler不了解,所以也不是很了解为什么会自动增加这样的代码;其实它是实现的IHttpHandler接口,对接口成员的一个实现;

2:若是使用到一般处理程序时有个地方要注意,就是它对Session值的读起时;运用上面的Handler.ashx是读不到Session值;实例如下:

我们定义一个NotSessionHandler.ashx用来读取Session的值:

<%@ WebHandler Language="C#" Class="NotSessionHandler" %>

using System;
using System.Web;

public class NotSessionHandler : IHttpHandler {

    public void ProcessRequest(HttpContext context)
    {
        Object SessionValue = context.Session["NotSession"];
        string Result = string.Empty;
        if (SessionValue != null) { Result = SessionValue.ToString(); }
        else
        {
            Result = "没有实现接口;Session的值无法读到";
        }
        context.Response.ContentType = "text/plain";
        context.Response.Write(Result);
    }
 
    public bool IsReusable {
        get {
            return false;
        }
    }
}

首先我们再Default.aspx页面进行写入Session值,并让NotSessionHandler.ashx显示:

    protected void Button4_Click(object sender, EventArgs e)
    {
        Session["NotSession"] = "踏浪帅";
        Response.Redirect("NotSessionHandler.ashx");
    }

运行结果如下(从下面不然发现读取失败):

为什么NotSessionHandler.ashx读取不到Session 的值?它不是已经有当前HttpContext上下文?其实NotSessionHandler.ashx还必须实现Session的一个重要接口IRequiresSessionState;其实接口IRequiresSessionState里并没有什么内容,只是一个简单的标识而已;它是存在于System.Web.SessionState内

接着我们实现对上面的NotSessionHandler.ashx进行修改,让它实现接口IRequiresSessionState;

using System;
using System.Web;
using System.Web.SessionState;
public class NotSessionHandler : IHttpHandler, IRequiresSessionState
{
    public void ProcessRequest(HttpContext context)
    {
        Object SessionValue = context.Session["NotSession"];
        string Result = string.Empty;
        if (SessionValue != null) { Result = SessionValue.ToString(); }
        else
        {
            Result = "没有实现接口;Session的值无法读到";
        }
        context.Response.ContentType = "text/plain";
        context.Response.Write(Result);
    }
 
    public bool IsReusable {
        get {
            return false;
        }
    }
}

运行结果:

三:自定义HttpHandler

1:自定义一个HttpHandler处理程序只要两步就可以实现了,第一是让类实现接口IHttpHandler,第二就是增加Web.config配置文件;

2:接下来我们将通过一个实例来演示对我们自个建的后缀类型进行访问;

步骤一:我们先建一个类MyHttpHandler类并实现接口IHttpHandler,此处只是显示内容;

using System.Web;
using System.IO;
using System.Text;
public class MyHttpHandler:IHttpHandler
{
    public MyHttpHandler()
    {

    }

    public bool IsReusable
    {
        get { return true; }
    }

    public void ProcessRequest(HttpContext context)
    {
        HttpRequest request = context.Request;
        HttpResponse response = context.Response;

        response.Write("这个是自定义的HttpHandler </br>");
        response.Write("访问URL地址:" + request.Url.Segments[2]+"</br>");
        string FileStr = request.PhysicalPath;
        if (File.Exists(FileStr))
        {
            response.Write("以下是文件Cnblogs.wujy的内容 <br/>");
            FileInfo fileInfo = new FileInfo(FileStr);
            StreamReader reader = new StreamReader(FileStr, Encoding.Default);
            string StrLine = string.Empty;
            while (!string.IsNullOrEmpty(StrLine = reader.ReadLine()))
            {
                response.Write(StrLine + "</br>");
            }
            reader.Close();
        }
        else
        {
            response.Write("文件不存在");
        }
    }
}

步骤二:在站点里我们新建一个Cnblogs.wujy的文件,此处的后缀名为:wujy 它是我自定义的一个后缀;Cnblogs.wujy文件内容:踏浪帅的地址www.cnblogs.com/wujy

步骤三:修改web.config配置;

    <httpHandlers>
      <add path="*.wujy" verb="*" type="MyHttpHandler"/>
    </httpHandlers>

运行效果如下(如果部署在IIS上可能要对后缀进行映射,在IIS里进行设置,不然这种可能在IIS那就直接访问不了):

上面我们是直接在VS运行时的情况,当我们部署在IIS要进行设置,不然在IIS里访问Cnblogs.wujy就会报下面的错误:

由于我本地的IIS为版7.0所以设置如下(若是IIS5或II6可以在应用程序扩展映射增加后缀):

3:接下来我们将通过一个实例,此实例是在ASP.Net夜话里看到的;实例主要实现一个对站点里的图片进行打水印的功能,这个功能是图片上传后在访问图片时打水印,它其实并不有把水印打在图片上只是访问时才显示出水印,保持图片的原来模样;

步骤一:我们新建一个实现接口IHttpHandler的类WaterMarkHandler:

using System;
using System.Web;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

/// <summary>
/// 动态给图片添加水印的类
/// </summary>
public class WaterMarkHandler:IHttpHandler
{
    public WaterMarkHandler()
    {
        
    }

    #region IHttpHandler 成员
    /// <summary>
    /// 指示其它请求是否可以使用这个实例,如果是true,则放入池中接受其它请求以提高请求
    /// </summary>
    public bool IsReusable
    {
        get { return true; }
    }
    /// <summary>
    /// 处理请求
    /// </summary>
    /// <param name="context">当前HTTP请求的上下文</param>
    public void ProcessRequest(HttpContext context)
    {
        //获取请求的物理图片路径
        string imagePath = context.Request.PhysicalPath;

        Image image = null;
        if (File.Exists(imagePath))
        {
            //定义水印文字
            string text = "给图片增加水印[踏浪帅]";
            //定义水印文字字体大小
            int fontSize = 12;
            //水印文字字体
            Font font = new Font("宋体", fontSize);
            //根据图片物理地址加载图片
            image = Image.FromFile(imagePath);
            Graphics g = Graphics.FromImage(image);
            //获取要绘制水印文字所需要的显示区域大小
            SizeF size=g.MeasureString(text, font);
            if (size.Width > image.Width || size.Height > image.Height)
            {
                //如果要显示的图片的尺寸都不足以显示按照指定字体来添加水印
                //可以减小字体大小或者不添加水印(太小了没办法添加嘛)
            }
            else//添加水印文字
            {
                Brush brush = Brushes.Red;
                //在图片上添加水印,绘制水印文字在图片的右下角
                g.DrawString(text, font, brush, image.Width - size.Width, image.Height - size.Height);
                g.Dispose();
            }
        }
        else//如果不存在,指定一个默认图片进行显示
        {
            imagePath = context.Server.MapPath("~/images/nopic.jpg");
            image = Image.FromFile(imagePath);
        }
        image.Save(context.Response.OutputStream, ImageFormat.Jpeg);//将添加水印的图片输入到当前流中
    }

    #endregion
}

步骤二:修改配置文件web.config(说明针对本站的图片都用上面的处理程序类处理)

    <httpHandlers>
      <add path="*.jpg" verb="*" type="WaterMarkHandler"/>
    </httpHandlers>

步骤三:我们新建一个页面用来显示图片:

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <img src="Image/1.jpg" alt="打水印"/>
    </div>
    </form>
</body>
</html>

运行查看效果图:

其实我们还有很多在平时开发中可能会用到自定义HttpHandler的功能,比如我们最常用的验证码功能和网站的图片防盗连功能等;

 

如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】按钮。  因为,我的写作热情也离不开您的肯定支持。
 
感谢您的阅读 [源代码下载]

 

 

最近有个妹子弄的一个关于扩大眼界跟内含的订阅号,每天都会更新一些深度内容,在这里如果你感兴趣也可以关注一下(嘿对美女跟知识感兴趣),当然可以关注后输入:github 会有我的微信号,如果有问题你也可以在那找到我;当然不感兴趣无视此信息;

posted @ 2013-08-18 15:18  踏浪帅  阅读(5842)  评论(8编辑  收藏