惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Y
Y Combinator Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
WordPress大学
WordPress大学
T
Threatpost
K
Kaspersky official blog
Cisco Talos Blog
Cisco Talos Blog
博客园 - 三生石上(FineUI控件)
Vercel News
Vercel News
T
Tenable Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
L
LINUX DO - 热门话题
Scott Helme
Scott Helme
云风的 BLOG
云风的 BLOG
博客园 - Franky
Webroot Blog
Webroot Blog
D
DataBreaches.Net
Stack Overflow Blog
Stack Overflow Blog
MongoDB | Blog
MongoDB | Blog
H
Help Net Security
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
F
Fortinet All Blogs
PCI Perspectives
PCI Perspectives
Google DeepMind News
Google DeepMind News
Microsoft Azure Blog
Microsoft Azure Blog
Blog — PlanetScale
Blog — PlanetScale
P
Proofpoint News Feed
Google DeepMind News
Google DeepMind News
月光博客
月光博客
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Help Net Security
Help Net Security
T
The Blog of Author Tim Ferriss
T
Tailwind CSS Blog
Hugging Face - Blog
Hugging Face - Blog
GbyAI
GbyAI
O
OpenAI News
Martin Fowler
Martin Fowler
W
WeLiveSecurity
C
Cyber Attacks, Cyber Crime and Cyber Security
Project Zero
Project Zero
V
Vulnerabilities – Threatpost
L
LangChain Blog
P
Privacy & Cybersecurity Law Blog
S
Security Affairs
P
Privacy International News Feed
C
Cybersecurity and Infrastructure Security Agency CISA
MyScale Blog
MyScale Blog
NISL@THU
NISL@THU
T
Troy Hunt's Blog
C
Cisco Blogs
IT之家
IT之家

博客园 - 永春

随笔 随笔 asp+access在64位上的问题 换个活法 项目做的很无语 五分钟叫你看懂美国金融危机的成因和巨大危害[转] Sqlserver中的日期类型值不能小于1753年 C#读取WORD时发生“拒绝访问”及“消息筛选器显示应用程序正在使用中”异常的处理 Asp.Net之自定义表达式构造器(ExpressionBuilder) [Sharepoint2007对象模型]第三回:Web应用程序(SPWebApplication) Sharepoint2007对象模型系列 [Sharepoint2007对象模型]第二回:Web应用程序服务(SPWebService) [Sharepoint2007对象模型]第一回:服务器场(SPFarm) C#强化系列文章九:代码访问安全性使用 项目经理的个人修养 《博客园精华集--Sharepoint分册》第三轮结果 《博客园精华集》Sharepoint+MOSS分册第2轮筛选结果文章列表 C#强化系列文章八:HttpModule,HttpHandler,HttpHandlerFactory简单使用 在MOSS中使用.Net3.5中的Ajax功能
Asp.Net页面执行流程分析
永春 · 2008-05-08 · via 博客园 - 永春

在我的上一篇文章中说到了HttpModule、HttpHandle的简单使用,我们可以利用它们在页面请求的过程中加入自己的事件处理程序。那么在一个aspx页面请求时后台到底做了什么?当然asp.net做了很多事情,过程也比较复杂,本文主要分析一下大体的流程。总体流程如下:
请求一个页面时首先被WWW服务截获(inetinfo.exe进程),这个进程首先判断页面的后缀,然后根据IIS中的配置来决定调用哪个扩展程序,比如aspx的页面就会调用c:\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll,aspnet_isapi.dll将请求发送给w3wp.exe进程(我们在调试IIS中网站时就是把VS2005附加到这个进程上的)。
接下来w3wp.exe进程就会调用.net类库进行具体处理:
ISAPIRuntime-->HttpRuntime-->HttpApplicationFactory-->HttpApplication-->HttpModule--HttpHandlerFactory-->HttpHandler 这也是本文主要分析的地方。下面只是列出主要流程,如果喜欢钻研的同学可以用Reflector去查看
一:ISAPIRuntime

       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;
        }

        HttpRuntime.ShutdownAppDomain(ApplicationShutdownReason.PhysicalApplicationPathChanged, SR.GetString(
"Hosting_Phys_Path_Changed"new object[] { appDomainAppPathInternal, appPathTranslated }));
        
return 1;

它的主要作用是调用一些非托管代码生成HttpWorkerRequest对象,该对象包含当前请求的所有信息,然后传递给HttpRuntime,这里生成的HttpWorkerRequest对象可以直接在我们的页面中调用的,通过它取得原始的请求信息:

            IServiceProvider provider = (IServiceProvider)HttpContext.Current;
            HttpWorkerRequest wr 
= (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest));


二:HttpRuntime

最主要的就是private void ProcessRequestInternal(HttpWorkerRequest wr)方法:

        context = new HttpContext(wr, false);
        
        IHttpHandler applicationInstance 
= HttpApplicationFactory.GetApplicationInstance(context);
        
  IHttpAsyncHandler handler2 
= (IHttpAsyncHandler) applicationInstance;
  context.AsyncAppHandler 
= handler2;
  handler2.BeginProcessRequest(context, 
this._handlerCompletionCallback, context);
        

1、根据HttpWorkerRequest对象生成HttpContext,HttpContext应该大家都很熟悉的,它包含request、response等属性,在页面中经常会用到的;
2、调用HttpApplicationFactory来生成IHttpHandler(这里生成的是一个默认的HttpApplication对象,HttpApplication也是IHttpHandler接口的一个实现)
3、调用HttpApplication对象执行请求

三:HttpApplicationFactory
正如2.2中所提到的,这里主要是生成一个HttpApplication对象:

 internal static string GetApplicationFile()
 
{
     
return Path.Combine(HttpRuntime.AppDomainAppPathInternal, "global.asax");
 }

首先会查看是否存在global.asax文件,如果有的话就用它来生成HttpApplication对象,从这里我们可以看到global.asax的文件名是在asp.net的框架中写死的,不能修改的。如果这个文件不存在就使用默认的对象。
创建好HttpApplication之后对它进行初始化:

    application = (HttpApplication) HttpRuntime.CreateNonPublicInstance(this._theApplicationType);
 
using (ApplicationImpersonationContext context2 = new ApplicationImpersonationContext())
 
{
     application.InitInternal(context, 
this._state, this._eventHandlerMethods);
 }


 四、HttpApplication
这个是比较复杂也比较重要的一个对象
首先是执行初始化操作,比较重要的一步就是进行HttpModule的初始化:

        private void InitModules()
        
{
            
this._moduleCollection = RuntimeConfig.GetAppConfig().HttpModules.CreateModules();
            
this.InitModulesCommon();
        }

它会读取web.config中所有HttpModule的配置
在HookupEventHandlersForApplicationAndModules方法中绑定Module的事件处理程序
接着进行事件实际绑定:

 if (HttpRuntime.UseIntegratedPipeline)
 
{
     
this._stepManager = new PipelineStepManager(this);
 }

 
else
 
{
     
this._stepManager = new ApplicationStepManager(this);
 }

 
this._stepManager.BuildSteps(this._resumeStepsWaitCallback);

在ApplicationStepManager的BuildSteps方法中可以看到事件的绑定执行顺序:

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(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());

注意上面红色标注的MapHandlerExecutionStep(读取所有的HttpHandler配置)、CallHandlerExecutionStep就是对Handle程序进行处理的,也就是说在web.config中配置的HttpHandler都是在这里进行处理的,执行顺序如上所示
 
然后就是调用2.3中的方法执行请求:

Code

在ResumeSteps中就是执行事件处理程序。 

五、HttpModule

在系统web.config中默认的配置有:

Code

基本使用方法可以参见我的上一篇文章

六、HttpHandlerFactory、HttpHandler

这两个对象在web.config中的配置方法是相同的,默认配置有:

Code

要注意的是相同的后缀名配置多次的话,后面的配置会把前面的覆盖。

这里我们重点看一下aspx的配置:System.Web.UI.PageHandlerFactory
这是一个HttpHandlerFactory对象,根据不同的Page生成不同的HttpHandler对象(我们自己的Page页面都是一个IHttpHandler):

    Page page = BuildManager.CreateInstanceFromVirtualPath(virtualPath, typeof(Page), context, truetrueas Page;
    
if (page == null)
    
{
        
return null;
    }

    page.TemplateControlVirtualPath 
= virtualPath;
    
return page;

这里会调用web.config中的buildProviders配置编译页面:

Code

这样就可以进入我们的Page执行了,大的执行顺序可以参见第四部分的描述,它也就是一个HttpHandler.