Net

Web流程-ISAPI处理

2018-04-13  本文已影响31人  Aneko

上一篇了解到 请求到达服务器后是怎么被IIS处理的,本篇来看一下在ISAPI内部是怎么处理请求的;

首先ISAPI 有三个重量级入口:
一, ISAPIRuntimeRequest.ProcessRequest() 最外层入口

  1. 根据句柄ecb创建HttpWorkerRequest 对象封装原始请求报文 wr ;
      public int ProcessRequest(IntPtr ecb, int iWRType)
        {
           ......
            ISAPIWorkerRequest wr = null;
            try
            {
                bool useOOP = iWRType == 1;
                wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP);
                wr.Initialize();
                string appPathTranslated = wr.GetAppPathTranslated();
                string appDomainAppPathInternal = HttpRuntime.AppDomainAppPathInternal;
                if ((appDomainAppPathInternal == null) || StringUtil.EqualsIgnoreCase(appPathTranslated, appDomainAppPathInternal))
                {
                    HttpRuntime.ProcessRequestNoDemand(wr);
                    return 0;
                }
           ......

1.1. 根据IIS版本来创建请求报文 ISAPIWorkerRequest

internal static ISAPIWorkerRequest CreateWorkerRequest(IntPtr ecb, bool useOOP)
        {
          ......
            if (num >= 7)
            {
                EtwTrace.TraceEnableCheck(EtwTraceConfigType.IIS7_ISAPI, ecb);
            }
            else
            {
                EtwTrace.TraceEnableCheck(EtwTraceConfigType.DOWNLEVEL, IntPtr.Zero);
            }
            if (EtwTrace.IsTraceEnabled(5, 1))
            {
                EtwTrace.Trace(EtwTraceType.ETW_TYPE_APPDOMAIN_ENTER, ecb, Thread.GetDomain().FriendlyName, null, true);
            }
            if (num >= 7)
            {
                return new ISAPIWorkerRequestInProcForIIS7(ecb);
            }
            if (num == 6)
            {
                return new ISAPIWorkerRequestInProcForIIS6(ecb);
            }
            return new ISAPIWorkerRequestInProc(ecb);
        }

二, HttpRuntime.ProcessRequestInternal()
1.根据HttpRuntime.ProcessRequestNoDemand(wr);方法内部创建HttpContext,HttpApplication对象;

 internal static void ProcessRequestNoDemand(HttpWorkerRequest wr)     
{             
            RequestQueue queue = _theRuntime(HttpRuntime实例)._requestQueue(请求队列);        
            wr.UpdateInitialCounters();        
            if (queue != null)          
            {            
                wr = queue.GetRequestToExecute(wr);  
            }
            if (wr != null)
            {
                CalculateWaitTimeAndUpdatePerfCounter(wr);
                wr.ResetStartTime();
                ProcessRequestNow(wr);
            }
 }

2.我们接着进入ProcessRequestNow(wr) 方法,方法根据请求报文开始创建HttpContext对象;

private void ProcessRequestInternal(HttpWorkerRequest wr)
        {
               ......
                HttpContext context;
                try
                {
                    context = new HttpContext(wr, false);

2.1. 这是实例HttpContext的方法,我们看到内部实例了常用对象 HttpRequest和HttpResponse

  internal HttpContext(HttpWorkerRequest wr, bool initResponseWriter)
        {
            this._timeoutStartTimeUtcTicks = -1L;
            this._timeoutTicks = -1L;
            this._threadAbortOnTimeout = true;
            this.ThreadContextId = new object();
            this._wr = wr;
            this.Init(new HttpRequest(wr, this), new HttpResponse(wr, this));
            if (initResponseWriter)
            {
                this._response.InitResponseWriter();
            }
            PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_EXECUTING);
        }
  1. 我们接下来看 HttpApplicationFactory.GetApplicationInstance(context) 方法内部通过维护一个应用程序池,当不存在时 实例化了HttpApplication(通过反射 Global.asax 文件);我们在这里发现原来IHttpHandler 是HttpApplication 的基类;
private void ProcessRequestInternal(HttpWorkerRequest wr)
                    ......
                    context.Response.InitResponseWriter();
                    IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(context);
                    ......
           
            }
        }

三. HttpApplication.Init() 管道事件

以上说了那么多废话,因为我们什么也改不了,只是对请求流程有个大致的了解;
下面我们就可以 跟微软达达互动了 (* ̄︶ ̄)

1.我们还是从 HttpApplication创建过程来看,我们注意到有一个InitInternal初始实例方法,在此方法中有两个 InitModules(),BuildSteps()方法;

  private HttpApplication GetNormalApplicationInstance(HttpContext context)
        {
            HttpApplication state = null;
           ......
            if (state == null)
            {
                state = (HttpApplication) HttpRuntime.CreateNonPublicInstance(this._theApplicationType);
                using (new ApplicationImpersonationContext())
                {
                    state.InitInternal(context, this._state, this._eventHandlerMethods);
                }
            }
            ......

2.在 InitModules方法中,通过读取Web.Config配置文件关于HttpModule信息,并加入集合;最后通过方法InitModulesCommon()遍历执行每个模块的初始化方法 Init();

 private void InitModules()
        {
            HttpModuleCollection modules = RuntimeConfig.GetAppConfig().HttpModules.CreateModules();
            HttpModuleCollection other = this.CreateDynamicModules();
            modules.AppendCollection(other);
            this._moduleCollection = modules;
            this.InitModulesCommon();
        }

3.在BuildSteps()方法中注册了管道事件,F12发现此方法是抽象方法,全局搜索找到; 方法结束时有一个CopyTo 方法,这个是把所有事件按顺序储存;

internal override void BuildSteps(WaitCallback stepCallback)
            {
                ArrayList steps = new ArrayList();
                HttpApplication app = base._application;
                bool flag = false;
                UrlMappingsSection urlMappings = RuntimeConfig.GetConfig().UrlMappings;
                flag = urlMappings.IsEnabled && (urlMappings.UrlMappings.Count > 0);
                steps.Add(new HttpApplication.ValidateRequestExecutionStep(app));
                steps.Add(new HttpApplication.ValidatePathExecutionStep(app));
                if (flag)
                {
                    steps.Add(new HttpApplication.UrlMappingsExecutionStep(app));
                }
// 管道事件
                app.CreateEventExecutionSteps(HttpApplication.EventBeginRequest, steps);
                app.CreateEventExecutionSteps(HttpApplication.EventAuthenticateRequest, steps);
                app.CreateEventExecutionSteps(HttpApplication.EventDefaultAuthentication, steps);
                app.CreateEventExecutionSteps(HttpApplication.EventPostAuthenticateRequest, steps);
                app.CreateEventExecutionSteps(HttpApplication.EventAuthorizeRequest, steps);
                app.CreateEventExecutionSteps(HttpApplication.EventPostAuthorizeRequest, steps);
                app.CreateEventExecutionSteps(HttpApplication.EventResolveRequestCache, steps);
                app.CreateEventExecutionSteps(HttpApplication.EventPostResolveRequestCache, steps);
                steps.Add(new HttpApplication.MapHandlerExecutionStep(app));
                app.CreateEventExecutionSteps(HttpApplication.EventPostMapRequestHandler, steps);
                app.CreateEventExecutionSteps(HttpApplication.EventAcquireRequestState, steps);
                app.CreateEventExecutionSteps(HttpApplication.EventPostAcquireRequestState, steps);
                app.CreateEventExecutionSteps(HttpApplication.EventPreRequestHandlerExecute, steps);
                steps.Add(app.CreateImplicitAsyncPreloadExecutionStep());
                steps.Add(new HttpApplication.CallHandlerExecutionStep(app));
                app.CreateEventExecutionSteps(HttpApplication.EventPostRequestHandlerExecute, steps);
                app.CreateEventExecutionSteps(HttpApplication.EventReleaseRequestState, steps);
                app.CreateEventExecutionSteps(HttpApplication.EventPostReleaseRequestState, steps);
                steps.Add(new HttpApplication.CallFilterExecutionStep(app));
                app.CreateEventExecutionSteps(HttpApplication.EventUpdateRequestCache, steps);
                app.CreateEventExecutionSteps(HttpApplication.EventPostUpdateRequestCache, steps);
                this._endRequestStepIndex = steps.Count;
                app.CreateEventExecutionSteps(HttpApplication.EventEndRequest, steps);
                steps.Add(new HttpApplication.NoopExecutionStep());
                this._execSteps = new HttpApplication.IExecutionStep[steps.Count];
                steps.CopyTo(this._execSteps);
                this._resumeStepsWaitCallback = stepCallback;
            }

4.我们依然回到ProcessRequestInternal方法中,执行BeginProcessRequest方法触发每个事件执行;

 if (applicationInstance is IHttpAsyncHandler)
                    {
                        IHttpAsyncHandler handler2 = (IHttpAsyncHandler) applicationInstance;
                        context.AsyncAppHandler = handler2;
                        handler2.BeginProcessRequest(context, this._handlerCompletionCallback, context);
                    }

四,模块和事件 ——管道

管道事件[http://www.cnblogs.com/edisonchou/p/4201855.html]

image.png

模块 IHttpmodule ,事件 IHttpHandler. 两种同属于请求处理注入逻辑,不同点在于 模块 针对于全部请求 逻辑注入,事件针对于指定文件 逻辑注入;

1.通过在<modules>节点下 配置模块,通过在 <handlers>节点下 配置事件,我们从它们配置项也可以看出来区别;

<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <!--<modules runAllManagedModulesForAllRequests="true" />-->
    <modules>
      <add name="CustomeModule" type="MVC3.CustomeModule, MVC3"  />
    </modules>
    <handlers>
      <add name="CustomeHandler" verb="*" path="*.txt" type="MVC3.CustomeHandler, MVC3"/>
    </handlers>
  </system.webServer>
  1. 实现相应的接口; 注意实现IHttpModule接口时Dispose方法的实现和IHttpHandler接口属性IsReusable 改为return true;
public class CustomeModule : IHttpModule
    {
        public void Dispose()
        {
            throw new NotImplementedException();
        }
        public void Init(HttpApplication context)
        {
            //context.Context.Response.Write("Module");
            context.BeginRequest += context_BeginRequest;
            context.PreRequestHandlerExecute += context_PreRequestHandlerExecute;
            context.PostRequestHandlerExecute += context_PostRequestHandlerExecute;
        }
        void context_PostRequestHandlerExecute(object sender, EventArgs e)
        {
            ((HttpApplication)sender).Context.Response.Write("PostRequestHandlerExecute   <br>  ");
        }
        void context_PreRequestHandlerExecute(object sender, EventArgs e)
        {
            ((HttpApplication)sender).Context.Response.Write("PreRequestHandlerExecute  <br>   ");
        }
        void context_BeginRequest(object sender, EventArgs e)
        {
            ((HttpApplication)sender).Context.Response.Write("BeginRequest  <br> ");
        }

    }
    public class CustomeHandler : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            context.Response.Write("CustomeHandler  <br>");
        }
        public bool IsReusable
        {
            get { return true; }
        }
    }

3.我们看页面执行结果,和管道事件的执行顺序是一致的

jpg
  1. 总结 常用思路:
    httphandler 可以运用在图片盗链上等等;httpmodule 可以用在权限等等;

参考文档 有直接使用博友的图,在此对以下博友表示感谢:
博客园[http://www.cnblogs.com/edisonchou/p/4195259.html]
博客园[http://www.cnblogs.com/edisonchou/p/4201855.html]
博客园[http://www.cnblogs.com/OceanHeaven/p/6514230.html]
博客园[https://www.cnblogs.com/Rayblog/p/6394315.html]
博客园[https://www.cnblogs.com/fish-li/archive/2013/01/04/2844908.html]
biancheng[http://www.bianceng.cn/Programming/net/201210/34557_3.htm]
MSDN iis与asp.net流程[https://msdn.microsoft.com/zh-cn/library/bb470252(v=vs.100).aspx]

上一篇下一篇

猜你喜欢

热点阅读