这篇文章花了点时间,差点成烂到电脑里面,写的过程中有好几次修改,最终的这个版本也不是很满意,东西说的不够细,还需要认真的去看下源码才能有所体会,先这样吧,后面有时间把细节慢慢的再修改。顺便对于开发的学习,个人是觉得源码的阅读是最快的提高方式,当然阅读不是走马观花,应该多次阅读。

上次说到获得HttpApplication对象的创建,创建完成后调用InitInternal方法,这个方法任务比较多,也比较长,这里就不贴全码了,一个一个过程的去说:

初始化HttpModule

对于HttpModule的认识,首先应该看下HttpModule的使用情况,下面通过一个简单的例子展示:

httpModule使用实例

  1. 新建一个项目,添加一个webform的窗体default.aspx,使用IIS添加到网站,应用程序池使用集成模式。
  2. 添加一个MyModule.cs,继承自IHttpModule。
  3. 在IHttpMoudule中有两个方法,在MyModule中必须要实现:

    public void Init(HttpApplication context)
    {
       throw new System.NotImplementedException();
    }public void Dispose()
    {
       throw new System.NotImplementedException();
    }

  4. 在Init方法中,有一个HttpApplication类型的对象context,这里可以对其中的响应的内容进行更改,修改如下:

    public void Init(HttpApplication context)
    {context.EndRequest += Context_EndRequest;
    }private void Context_EndRequest(object sender, System.EventArgs e)
    {var context = (HttpApplication) sender;context.Response.Write("<h1>Hello MyModule</h1>");
    }

  5. 添加web.config文件如下(在 system.webServer下 modules节点下面):

    <add name="MyModule" type="Application.MyModule,Application"/>

    运行结果:

  6. 在上面的例子中,使用的是集成模式,当改成经典模式的时候,module又不起作用了。对于经典模式的配置文件与集成模式不同。经典模式的配置文件如下:

    <httpModules>
       <add name="MyModule" type="IISIntegratedPipeline.MyModule,IISIntegratedPipeline"/>
    </httpModules>

  7. 对于 module的使用,有了一个简单的认识,在asp.net中module是一个灵活的配置,可以对请求进行自定义的处理,对于Asp.net如何处理的,在下面详细解说。

asp.net中HttpModule的处理

  1. 结合上面例子,HttpModule在Asp.net中有重要的作用,可以HttpApplication的事件进行订阅,也可以修改对应的响应的内容

  2. 对于HttpModule的初始化,asp.Net中会根据当前应用程序池的类型进行初始化,核心代码如下:

    if (HttpRuntime.UseIntegratedPipeline) {try {context.HideRequestResponse = true;_hideRequestResponse = true;InitIntegratedModules();
    }
    finally {context.HideRequestResponse = false;_hideRequestResponse = false;}
    }
    else {InitModules();}

  3. 对于Module的理解,需要根据应用程序池的模式来处理(经典和集成)。
  4. 对于集成模式,获得所有Modules的方法是调用非托管的方法的进行获得,具体获得的代码如下:

    • InitIntegratedModules的方法

      private void InitIntegratedModules()
      {_moduleCollection = BuildIntegratedModuleCollection(_moduleConfigInfo);InitModulesCommon();
      }

    • _moduleConfigInfo 的来源
      这个_moduleConfigInfo的来源,还需要追到上篇 HttpApplication中三个方法的调用(EnsureAppStartCalled 第二个方法的调用)具体调用步骤如下:

         [DllImport(_IIS_NATIVE_DLL)]internal static extern int MgdGetModuleCollection(IntPtr pConfigSystem,IntPtr appContext,out IntPtr pModuleCollection,out int count);

  5. 对于经典模式获得Modules简单的多,直接获得是调用配置文件

    private void InitModules()
    {HttpModulesSection pconfig = RuntimeConfig.GetAppConfig().HttpModules;// get the static list, then add the dynamic membersHttpModuleCollection moduleCollection = pconfig.CreateModules();HttpModuleCollection dynamicModules = CreateDynamicModules();moduleCollection.AppendCollection(dynamicModules);_moduleCollection = moduleCollection; // don't assign until all ops have succeeded
    InitModulesCommon();
    }

  6. 最终会调用 InitModulesCommon方法,循环调用Modules中的方法

     private void InitModulesCommon(){int n = _moduleCollection.Count;for (int i = 0; i < n; i++) {_currentModuleCollectionKey = _moduleCollection.GetKey(i);_moduleCollection[i].Init(this);}_currentModuleCollectionKey = null;InitAppLevelCulture();}

Global内的方法调用

对于Global方法的调用,是调用HookupEventHandlersForApplicationAndModules(handlers);方法,这里的Handlers的收集和创建来源于上篇讲HttpAplication的三个方法调用的第一个方法。具体的看下上次的代码,这里不多叙述。对于方法的handlers的调用的核心代码如下,其实也是一个循环加上判断:

 for (int i = 0; i < handlers.Length; i++) {MethodInfo appMethod = handlers[i];String appMethodName = appMethod.Name;int namePosIndex = appMethodName.IndexOf('_');String targetName = appMethodName.Substring(0, namePosIndex);...ParameterInfo[] addMethodParams = addMethod.GetParameters();if (addMethodParams.Length != 1)continue;Delegate handlerDelegate = null;ParameterInfo[] appMethodParams = appMethod.GetParameters();...try {addMethod.Invoke(target, new Object[1]{handlerDelegate});}catch {if (HttpRuntime.UseIntegratedPipeline) {throw;}}if (eventName != null) {if (_pipelineEventMasks.ContainsKey(eventName)) {if (!StringUtil.StringStartsWith(eventName, "Post")) {_appRequestNotifications |= _pipelineEventMasks[eventName];}else {_appPostNotifications |= _pipelineEventMasks[eventName];}}}
}

根据应用程序池的类型创建不同的_stepManager

这里很简单,直接看代码:

// Construct the execution steps array
if (HttpRuntime.UseIntegratedPipeline) {_stepManager = new PipelineStepManager(this);
}
else {_stepManager = new ApplicationStepManager(this);
}

执行BuildStep

BuildStep与ResumeStep是Asp.net的核心运行环节。同样,在经典模式与集成模式下原理和过程也有所不一样。

集成模式

  1. 下面先讨论集成模式下是如何进行的。

    internal override void BuildSteps(WaitCallback stepCallback){HttpApplication app = _application;IExecutionStep materializeStep = new MaterializeHandlerExecutionStep(app);app.AddEventMapping(HttpApplication.IMPLICIT_HANDLER,RequestNotification.MapRequestHandler,false, materializeStep);app.AddEventMapping(HttpApplication.IMPLICIT_HANDLER,RequestNotification.ExecuteRequestHandler,false, app.CreateImplicitAsyncPreloadExecutionStep());IExecutionStep handlerStep = new CallHandlerExecutionStep(app);app.AddEventMapping(HttpApplication.IMPLICIT_HANDLER,RequestNotification.ExecuteRequestHandler,false, handlerStep);IExecutionStep webSocketsStep = new TransitionToWebSocketsExecutionStep(app);app.AddEventMapping(HttpApplication.IMPLICIT_HANDLER,RequestNotification.EndRequest,true /* isPostNotification */, webSocketsStep);IExecutionStep filterStep = new CallFilterExecutionStep(app);app.AddEventMapping(HttpApplication.IMPLICIT_FILTER_MODULE,RequestNotification.UpdateRequestCache,false, filterStep);app.AddEventMapping(HttpApplication.IMPLICIT_FILTER_MODULE,RequestNotification.LogRequest,false, filterStep);_resumeStepsWaitCallback = stepCallback;}

  2. 上面的代码是核心是AddEventMapping方法,把相关的步骤添加到一个PipelineModuleStepContainer.

    private void AddEventMapping(string moduleName,RequestNotification requestNotification,bool isPostNotification, IExecutionStep step)
    {ThrowIfEventBindingDisallowed();if (!IsContainerInitalizationAllowed) {return;}PipelineModuleStepContainer container = GetModuleContainer(moduleName);if (container != null) {container.AddEvent(requestNotification, isPostNotification, step);}
    }

经典模式

1.看下代码:

internal override void BuildSteps(WaitCallback stepCallback ) {ArrayList steps = new ArrayList();HttpApplication app = _application;bool urlMappingsEnabled = false;UrlMappingsSection urlMappings = RuntimeConfig.GetConfig().UrlMappings;urlMappingsEnabled = urlMappings.IsEnabled && ( urlMappings.UrlMappings.Count > 0 );steps.Add(new ValidateRequestExecutionStep(app));steps.Add(new ValidatePathExecutionStep(app));if (urlMappingsEnabled)steps.Add(new UrlMappingsExecutionStep(app)); // url mappings
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 MapHandlerExecutionStep(app)); // map handler
        app.CreateEventExecutionSteps(HttpApplication.EventPostMapRequestHandler, steps);app.CreateEventExecutionSteps(HttpApplication.EventAcquireRequestState, steps);app.CreateEventExecutionSteps(HttpApplication.EventPostAcquireRequestState, steps);app.CreateEventExecutionSteps(HttpApplication.EventPreRequestHandlerExecute, steps);steps.Add(app.CreateImplicitAsyncPreloadExecutionStep()); // implict async preload stepsteps.Add(new CallHandlerExecutionStep(app)); // execute handler
        app.CreateEventExecutionSteps(HttpApplication.EventPostRequestHandlerExecute, steps);app.CreateEventExecutionSteps(HttpApplication.EventReleaseRequestState, steps);app.CreateEventExecutionSteps(HttpApplication.EventPostReleaseRequestState, steps);steps.Add(new CallFilterExecutionStep(app)); // filtering
        app.CreateEventExecutionSteps(HttpApplication.EventUpdateRequestCache, steps);app.CreateEventExecutionSteps(HttpApplication.EventPostUpdateRequestCache, steps);_endRequestStepIndex = steps.Count;app.CreateEventExecutionSteps(HttpApplication.EventEndRequest, steps);steps.Add(new NoopExecutionStep()); // the last is always there
_execSteps = new IExecutionStep[steps.Count];steps.CopyTo(_execSteps);_resumeStepsWaitCallback = stepCallback;}

对于上面的代码,可以看出都调用了 CreateEventExecutionSteps 方法,这个方法的详细如下 :

 private void CreateEventExecutionSteps(Object eventIndex, ArrayList steps) {// asyncAsyncAppEventHandler asyncHandler = AsyncEvents[eventIndex];if (asyncHandler != null) {asyncHandler.CreateExecutionSteps(this, steps);}EventHandler handler = (EventHandler)Events[eventIndex];if (handler != null) {Delegate[] handlers = handler.GetInvocationList();for (int i = 0; i < handlers.Length; i++) {steps.Add(new SyncEventExecutionStep(this, (EventHandler)handlers[i]));}}}

可以看出, CreateEventExecutionSteps是把注册的步骤都转换成了SyncEventExecutionStep,最终会被按顺序进行调用。

执行BeginProcessRequest

HttpApplication在完成BuildSteps的时候,把生成的App经过层层返回到HttpRuntime,前面几篇文章提到,在HttpRuntime里面有对app的类型进行判断,如果是IHttpAsyncHandler直接调用BeginProcessRequest方法,具体的代码如下:

 if (app is IHttpAsyncHandler) {IHttpAsyncHandler asyncHandler = (IHttpAsyncHandler)app;context.AsyncAppHandler = asyncHandler;asyncHandler.BeginProcessRequest(context, _handlerCompletionCallback, context);}else {// synchronous handler
            app.ProcessRequest(context);FinishRequest(context.WorkerRequest, context, null);}

BeginProcessRequest 方法:

IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) {HttpAsyncResult result;_context = context;_context.ApplicationInstance = this;_stepManager.InitRequest();_context.Root();result = new HttpAsyncResult(cb, extraData);AsyncResult = result;if (_context.TraceIsEnabled)HttpRuntime.Profile.StartRequest(_context);ResumeSteps(null);return result;}

其中最核心的方法是ResumeSteps方法,具体如下:

internal override void ResumeSteps(Exception error)
{for (; ; ) {// ...
IExecutionStep step = _application.CurrentModuleContainer.GetNextEvent(context.CurrentNotification, context.IsPostNotification,context.CurrentModuleEventIndex);context.SyncContext.Enable();stepCompletedSynchronously = false;//*******error = _application.ExecuteStep(step, ref stepCompletedSynchronously);//*********
        ...if (!stepCompletedSynchronously) {_application.AcquireNotifcationContextLock(ref locked);context.NotificationContext.PendingAsyncCompletion = true;break;}else {context.Response.SyncStatusIntegrated();}}
}

对于上面的内容总结原理为:

写于 2017.03.21

转载于:https://www.cnblogs.com/OceanHeaven/p/6597370.html

第37篇 Asp.Net源码解析(二)--详解HttpApplication相关推荐

  1. 《Attention is all you need》源码解析+算法详解

    Attention is all you need 源码解析 最近学习Transformer模型的时候,并且好好读了一下Google的<Attention is all you need> ...

  2. spring boot 源码解析43-JmxMetricWriter详解

    前言 本文我们来介绍JmxMetricWriter, JmxMetricWriter是依赖于spring jmx 来实现的. 因此本文的开头先介绍一下spring boot 与jmx的集成,然后分析J ...

  3. gauge对应的JAVA类型_spring boot 源码解析38-GaugeService详解

    前言 本文来分析GaugeService的实现,其类图如下: 解析 GaugeService GaugeService–> 1个可以用来提交1个被命名的duble值为了存储和分析的服务.任意的统 ...

  4. 【深度学习模型】智云视图中文车牌识别源码解析(二)

    [深度学习模型]智云视图中文车牌识别源码解析(二) 感受 HyperLPR可以识别多种中文车牌包括白牌,新能源车牌,使馆车牌,教练车牌,武警车牌等. 代码不可谓不混乱(别忘了这是职业公司的准产品级代码 ...

  5. Spring IoC源码:getBean 详解

    文章目录 Spring源码系列: 前言 正文 方法1:getObjectForBeanInstance 方法2:getObjectFromFactoryBean 方法3:doGetObjectFrom ...

  6. Android4.0源码目录结构详解

    Android4.0源码目录结构详解 Android4.0与2.1目录差不多 alsa这块,注意external/tinyalsa下有: include/tinyalsa/asoundlib.h mi ...

  7. Android 8.0学习(32)---Android 8.0源码目录结构详解

    Android 8.0源码目录结构详解 android的移植按如下流程:     (1)android linux 内核的普通驱动移植,让内核可以在目标平台上运行起来.     (2)正确挂载文件系统 ...

  8. FreeRTOS之源码 及 移植详解

    源:FreeRTOS之源码 及 移植详解 转载于:https://www.cnblogs.com/LittleTiger/p/9117856.html

  9. Nginx源码包安装详解

    源码包安装详解 1.源码获取 2.如何安装源码 3.源码获取存放 3.1创建源码存放目录 3.2把源码移到需要存放的目录 3.3解压文件 3.4常用命令介绍 4.源码安装实际操作 4.1官网获取源码包 ...

最新文章

  1. Nmap帮助文档解释
  2. 仅支持chrome的滚动条样式
  3. 365Rss.cn Beta 1.0 (内测版本)更新 2007-1-18:速度、人性化、简洁化
  4. c语言数组在栈上的分配,彻底弄懂为什么不能把栈上分配的数组(字符串)作为返回值...
  5. 芯片-模组-开发板-软件开发包SDK(Software Development Kit)的关系(软件开发人员必须了解的硬件知识)
  6. matlab 2010 win7 64位,64位WIN7系统怎么安装Matlab2010
  7. 如何成为一个伟大的 JavaScript 程序员
  8. 首次合作带给我的感想
  9. windows8中的数据上下文和简单的ListView
  10. JS 对GridView的一些操作
  11. Linux Kbuild文档 2
  12. 基于java ssm springboot女士电商平台系统源码+文档设计
  13. JVM Specification 9th Edition (4) Chapter 3. Compiling for the Java Virtual Machine
  14. 基于单片机程控滤波放大器增益设计-protues仿真
  15. 【AR优秀开源项目】ARCore项目工程汇总
  16. 笔记本电脑耳机插入后声音还是外放的解决办法
  17. 移动警务整体解决方案_辅助或替代人类的技术无法解决警务问题
  18. 网络应用的基本原理(基础 !非常重要!)
  19. 数据分析的思维逻辑步骤
  20. 人工智能守护青山绿水 内蒙古环保厅引入阿里云ET环境大脑

热门文章

  1. 微信小程序实现图书管理系统
  2. 基于Javaweb实现人力资源管理系统
  3. Generator + Promises, the best of all worlds in ES6
  4. 攻击NLP模型:通用对抗触发器入门
  5. 基于InfluxDB实现分页查询功能
  6. c语言学习笔记-if语句块一定要加分号
  7. 用SAXBuilder、Document、Element操作xml
  8. linux7系统怎么启动ftp,教你如何在CentOS7系统中配置ftp服务
  9. python封装api给vue_vue的封装
  10. jsp超链接中怎么跳转页面跳转_JSP页面跳转方法小结