zoukankan      html  css  js  c++  java
  • 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:WindowsMicrosoft.NETFrameworkv4.0.30319Configweb.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后缀的路径:

    本文参考文档:

  • 相关阅读:
    初识sql语句
    IO模型比较分析
    select,poll,epoll,selectors
    多路复用IO
    非阻塞IO
    yield-from示例
    阻塞IO(blocking IO)
    IO模型介绍
    gevent实现套接字
    gevent异步,io自动切换
  • 原文地址:https://www.cnblogs.com/Dewumu/p/13813163.html
Copyright © 2011-2022 走看看