Asp.net 处理程序&处理程序接口IHttpHandler
作者:互联网
通过Asp.Net构架(Http请求处理流程)和HttpApplication处理对象与HttpModule处理模块前面两篇我们了解了Http请求在服务器端的处理流程,Http请求最终会由实现了IHttpHandler接口的类进行处理,针对不同的请求,Asp.net要有不同的处理。通常情况下,HTTP.SYS根据请求的扩展名来确定ISAPI处理程序,再通过各种处理程序来分别进行处理。
回顾一下Http请求处理流程:
- 当Http请求进入 Asp.Net Runtime以后,它的管道由托管模块(NOTE:Managed Modules)和处理程序(NOTE:Handlers)组成,并且由管道来处理这个 Http请求
- HttpRuntime将Http请求转交给 HttpApplication,HttpApplication代表着程序员创建的Web应用程序。HttpApplication创建针对此Http请求的 HttpContext对象,这些对象包含了关于此请求的诸多其他对象,主要是HttpRequest、HttpResponse、HttpSessionState等
- 接下来Http请求通过一系列Module,这些Module对Http请求具有完全的控制权。这些Module可以做一些执行某个实际工作前的事情。
- Http请求经过所有的Module之后,它会被HttpHandler处理。
- HttpHandler处理完以后,Http请求再一次回到Module,此时Module可以做一些某个工作已经完成了之后的事情。
HttpModule源码
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Activation
{
using System.Diagnostics;
using System.Runtime;
using System.Security;
using System.ServiceModel;
using System.Web;
using System.Web.Hosting;
class HttpModule : IHttpModule
{
static bool disabled;
[Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - called outside PermitOnly context.")]
public void Dispose()
{
}
[Fx.Tag.SecurityNote(Critical = "Entry-point from asp.net, accesses ProcessRequest which is SecurityCritical.")]
[SecurityCritical]
public void Init(HttpApplication context)
{
context.PostAuthenticateRequest += new EventHandler(ProcessRequest);
}
[Fx.Tag.SecurityNote(Critical = "Entry-point from asp.net, called outside PermitOnly context. ASP calls are critical." +
"HostedHttpRequestAsyncResult..ctor is critical because it captures HostedImpersonationContext." +
"(and makes it available later) so caller must ensure that this is called in the right place.")]
[SecurityCritical]
static void ProcessRequest(object sender, EventArgs e)
{
if (HttpModule.disabled)
{
return;
}
try
{
ServiceHostingEnvironment.SafeEnsureInitialized();
}
catch (SecurityException exception)
{
HttpModule.disabled = true;
DiagnosticUtility.TraceHandledException(exception, TraceEventType.Warning);
// If requesting a .svc file, the HttpHandler will try to handle it. It will call
// SafeEnsureInitialized() again, which will fail with the same exception (it is
// idempotent on failure). This is the correct behavior.
return;
}
HttpApplication application = (HttpApplication)sender;
// Check to see whether the extension is supported
string extension = application.Request.CurrentExecutionFilePathExtension;
if (string.IsNullOrEmpty(extension))
{
return;
}
ServiceHostingEnvironment.ServiceType serviceType = ServiceHostingEnvironment.GetServiceType(extension);
// do extension check first so that we do not need to do it in aspnetrouting/configurationbasedactivation
if (serviceType == ServiceHostingEnvironment.ServiceType.Unknown)
{
return;
}
// check for AspNetcompat
if (ServiceHostingEnvironment.AspNetCompatibilityEnabled)
{
// remap httphandler for xamlx in CBA, since there is No physical file and
// the xamlx httphandlerfactory will do file exist checking
if (serviceType == ServiceHostingEnvironment.ServiceType.Workflow && ServiceHostingEnvironment.IsConfigurationBasedService(application))
{
application.Context.RemapHandler(new HttpHandler());
}
return;
}
else if (serviceType == ServiceHostingEnvironment.ServiceType.WCF)
{
HostedHttpRequestAsyncResult.ExecuteSynchronous(application, false, false);
}
else if (serviceType == ServiceHostingEnvironment.ServiceType.Workflow)
{
HostedHttpRequestAsyncResult.ExecuteSynchronous(application, false, true);
}
}
}
}
HttpHandler源码
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Activation
{
using System.Runtime;
using System.Security;
using System.ServiceModel;
using System.Web;
using System.Web.SessionState;
class HttpHandler : IHttpHandler, IRequiresSessionState
{
public bool IsReusable
{
[Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - called outside PermitOnly context.")]
get
{
return true;
}
}
[Fx.Tag.SecurityNote(Critical = "Entry-point from asp.net, called outside PermitOnly context.")]
[SecurityCritical]
public void ProcessRequest(HttpContext context)
{
ServiceHostingEnvironment.SafeEnsureInitialized();
HostedHttpRequestAsyncResult.ExecuteSynchronous(context.ApplicationInstance, true, false);
}
}
}
IHttpHandler
在Asp.net中,所有的处理程序类必须实现IHttpHandler接口或者实现IHttpAsyncHandler接口,一个同步,一个异步。
IHttpHandler的定义如下:
//------------------------------------------------------------------------------
// <copyright file="IHttpHandler.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
/*
* Synchronous Http request handler interface
*
* Copyright (c) 1998 Microsoft Corporation
*/
namespace System.Web {
using System.Security.Permissions;
/// <devdoc>
/// <para>
/// Defines the contract that developers must implement to
/// synchronously process HTTP web requests. Developers
/// implement the ProcessRequest method to provide custom URL execution.
/// </para>
/// </devdoc>
public interface IHttpHandler {
/// <devdoc>
/// <para>
/// Drives web processing execution.
/// </para>
/// </devdoc>
void ProcessRequest(HttpContext context);
/// <devdoc>
/// <para>
/// Allows an IHTTPHandler instance to indicate at the end of a
/// request whether it can be recycled and used for another request.
/// </para>
/// </devdoc>
bool IsReusable { get; }
}
}
- IsReusable属性表示:“当这个处理程序对象在使用之后,是否还可以被缓存起来,在以后的请求处理中再次使用”,这个属性主要用来配合处理程序工厂使用
- ProcessRequest是IHttpHandler接口的主要方法,接收并通过一个HttpContext类型的请求上下文对象,处理程序可以得到关于处理请求所需的信息。通过HttpContext的Response属性可以得到响应的对象,用以向客户端返回服务器处理的结果。
IHttpAsyncHandler
IHttpAsyncHandler比IHttpHandler增加了两个方法,BeginProcessRequest和EndProcessRequest方法。
//------------------------------------------------------------------------------
// <copyright file="IHttpAsyncHandler.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
/*
* Asynchronous Http request handler interface
*
* Copyright (c) 2000 Microsoft Corporation
*/
namespace System.Web {
using System.Security.Permissions;
/// <devdoc>
/// <para>When implemented by a class, defines the contract that Http Async Handler objects must
/// implement.</para>
/// </devdoc>
public interface IHttpAsyncHandler : IHttpHandler {
/// <devdoc>
/// <para>Registers handler for async notification.</para>
/// </devdoc>
IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData);
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
void EndProcessRequest(IAsyncResult result);
}
}
处理程序工厂IHttpHandlerFactory
//------------------------------------------------------------------------------
// <copyright file="IHttpHandlerFactory.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
/*
* Handler factory interface
*/
namespace System.Web {
using System.Security.Permissions;
/*
* Handler factory -- gets Handler by requestType,path,file
*/
/// <devdoc>
/// <para>
/// Defines the contract that factories must implement to dynamically
/// create IHttpHandler instances.
/// </para>
/// </devdoc>
public interface IHttpHandlerFactory {
/// <devdoc>
/// <para>
/// Returns an instance of an IHttpHandler class.
/// </para>
/// </devdoc>
IHttpHandler GetHandler(HttpContext context, String requestType, String url, String pathTranslated);
/// <devdoc>
/// <para>
/// Enables a factory to recycle or re-use an existing handler
/// instance.
/// </para>
/// </devdoc>
void ReleaseHandler(IHttpHandler handler);
}
internal interface IHttpHandlerFactory2 : IHttpHandlerFactory {
/// <devdoc>
/// <para>
/// Returns an instance of an IHttpHandler class. Works directly with a VirtualPath object
/// to avoid unnecessary conversions and creations.
/// </para>
/// </devdoc>
IHttpHandler GetHandler(HttpContext context, String requestType, VirtualPath virtualPath, String physicalPath);
}
}
- GetHandler方法用来通过这个处理程序工厂获取一个处理程序对象
- ReleaseHandler方法用来释放一个处理程序对象
注册处理程序
每一种处理程序用来处理一类请求,不同的请求类别通过请求的扩展名来进行区分,处理程序与请求之间的匹配关系在网站的配置文件web.config中通过配置参数来进行设置。system.web配置元素的子元素httpHandlers用来配置网站所使用的处理程序。httpHandlers元素可以包含三种子元素:add、remove和clear。
add子元素有三个必选的属性,作用如下:
- verb通过一个逗号(,)分割的HTTP请求类型列表来表示处理请求的类型
- eg:GET,POST等;使用星号(*)表示处理所有类型的请求。
- path通过一个固定的URL路径或者一个使用星号(*)的通配符来匹配请求的URL
- eg:使用*.aspx表示这个处理请求将处理所有扩展名为aspx的请求。
- type处理程序的类型名称,或者是处理程序工厂的类型名称,这个类型必须是类型的全名,包含命名空间、程序集(当类放在私有程序集时)。
- validate为可选的属性,如果设置为false,那么Asp.net在第一次匹配的请求调用之前,将不会试图加载这个类。
在网站应用程序运行的时候,实际得到的配置文件来自于系统的machine.config,系统的web.config和网站自身的web.config合并。在web.config中Asp.net已经预先配置了57中处理程序的映射,还可以通过处理程序接口扩展自定义的处理程序。
系统的web.config路径:C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\web.config
<httpHandlers>
<add path="eurl.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="True"/>
<add path="trace.axd" verb="*" type="System.Web.Handlers.TraceHandler" validate="True"/>
<add path="WebResource.axd" verb="GET" type="System.Web.Handlers.AssemblyResourceLoader" validate="True"/>
<add verb="*" path="*_AppService.axd" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="False"/>
<add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="False"/>
<add path="*.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="True"/>
<add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="True"/>
<add path="*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" validate="True"/>
<add path="*.asmx" verb="*" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="False"/>
<add path="*.rem" verb="*" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="False"/>
<add path="*.soap" verb="*" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="False"/>
<add path="*.asax" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.ascx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.master" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.skin" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.browser" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.sitemap" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.dll.config" verb="GET,HEAD" type="System.Web.StaticFileHandler" validate="True"/>
<add path="*.exe.config" verb="GET,HEAD" type="System.Web.StaticFileHandler" validate="True"/>
<add path="*.config" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.cs" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.csproj" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.vb" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.vbproj" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.webinfo" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.licx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.resx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.resources" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.mdb" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.vjsproj" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.java" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.jsl" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.ldb" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.ad" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.dd" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.ldd" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.sd" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.cd" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.adprototype" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.lddprototype" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.sdm" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.sdmDocument" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.mdf" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.ldf" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.exclude" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.refresh" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.svc" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="False"/>
<add path="*.rules" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.xoml" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="False"/>
<add path="*.xamlx" verb="*" type="System.Xaml.Hosting.XamlHttpHandlerFactory, System.Xaml.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="False"/>
<add path="*.aspq" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.cshtm" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.cshtml" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.vbhtm" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.vbhtml" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*" verb="GET,HEAD,POST" type="System.Web.DefaultHttpHandler" validate="True"/>
<add path="*" verb="*" type="System.Web.HttpMethodNotAllowedHandler" validate="True"/>
</httpHandlers>
以上是系统默认的处理程序映射
自定义处理程序
这个类定义在命名空间TestMeb.Utility下,名为ValidateCodeHandler,实现IHttpHandler接口。为了在处理程序中使用Session状态管理,同时实现IRequiresSessionState接口。这个类定义在私有程序集TestMeb.dll中,用来处理GET类型的请求,请求的扩展名为vc,那么在网站项目的配置文件web.config中注册这个处理程序,配置参数如下
<system.webServer>
<handlers>
<add name="ValidateCode" verb="GET" path="*.vc" type="TestMeb.Utility.ValidateCodeHandler,TestMeb"/>
</handlers>
</system.webServer>
新建一个Asp.net Web程序:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Web;
using System.Web.SessionState;
namespace TestMeb.Utility
{
public class ValidateCodeHandler : IHttpHandler, IRequiresSessionState
{
private static Random random = new Random();
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "image/jpeg";
Image image = new Bitmap(60, 30);
//生成随机数
int code = random.Next(1000, 10000);
string codeString = code.ToString();
//使用会话状态
context.Session["Code"] = codeString;
using (Graphics g = Graphics.FromImage(image))
{
g.Clear(Color.WhiteSmoke);
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
g.DrawString(codeString, new Font("Arial", 14), Brushes.Blue, new RectangleF(0, 0, image.Width, image.Height), sf);
}
context.Response.ContentType = "image/jpeg";
image.Save(context.Response.OutputStream, ImageFormat.Jpeg);
}
public bool IsReusable
{
get { return false; }
}
}
}
因为项目是在MVC中建立的,因此需要在MVC路由中添加忽略,避免程序走MVC流程,
在RouteConfig中添加
routes.IgnoreRoute("Remote/{*pathInfo}");
忽略网站根目录下Remote的请求,启动项目,随便打开一个本系统下.vc后缀的路径:
本文参考文档:
标签:Asp,请求,程序接口,System,IHttpHandler,处理程序,context,using 来源: https://www.cnblogs.com/Dewumu/p/13813163.html