昨天写的浏览器向服务器请求页面的原理,主要是讲了关于请求静态页面的,今天讲讲服务器处理动态页面

今天用一般处理程序(.ashx)来讲解,一般处理程序是asp.net的核心。

一般处理程序(HttpHandler): 是一个实现System.Web.IHttpHandler特殊接口的类。 能够作为一个外部请求的目标程序的前提是必须实现了IHttpHandler接口。(凡是没有实现此接口的类,就不能被浏览器请求。)

接昨天写的:

IIS发现请求的页面是动态页面,一看自己处理不了,于是就把该请求转交给了IIS的可扩展程序aspnet_isapi.exe,该扩展程序又交给了.NetFrameWork,.net内部处理是通过ISAPIRuntime等一系列操作实现的,首先创建ISAPIRuntime的对象,而后调用自己的ProcessRequest方法来处理请求:

第一步:在ProcessRequst中创建ISAPIWorkerRequest 并且讲ISAPIWorkerRequest 作为参数传给了HttpRuntime的ProcessRequestNoDemand方法

public sealed class ISAPIRuntime : MarshalByRefObject, IISAPIRuntime, IRegisteredObject
{
    public int ProcessRequest(IntPtr ecb, int iWRType)
    {
        ...........
        ISAPIWorkerRequest wr = null;
        try
        {
            bool useOOP = iWRType == 1;
           wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP);//通过调用静态方法CreateWorkerRequest创建ISAPIWorkerRequest            wr.Initialize();
            ........................
            if ((appDomainAppPathInternal == null) || StringUtil.EqualsIgnoreCase(appPathTranslated, appDomainAppPathInternal))
            {
                HttpRuntime.ProcessRequestNoDemand(wr);
                return 0;
            }
            ..............
        }
        catch (Exception exception)
        {
            ..........
        }
    }
}

第二步:接下来有是什么呢,我么来看看ProcessRequestNoDemand(wr)这个方法:

internal static void ProcessRequestNoDemand(HttpWorkerRequest wr)
{
    RequestQueue queue = _theRuntime._requestQueue;//拿到了一个请求队列
    wr.UpdateInitialCounters();
    if (queue != null)
    {
        wr = queue.GetRequestToExecute(wr);//哇,在这里才是正的创建出了HttpWorkerRequest,这里可是包含有请求上下文啊
    }
    if (wr != null)
    {
        CalculateWaitTimeAndUpdatePerfCounter(wr);
        wr.ResetStartTime();
        ProcessRequestNow(wr);//嗯?怎么wr怎么又被传出去了,接下来再看看这个方法有干了写什么
    }
}

第三步:接这查看一下ProcessRequestNow(wr)方法:

internal static void ProcessRequestNow(HttpWorkerRequest wr)
{
    _theRuntime.ProcessRequestInternal(wr);//又是作为参数来传了,继续看看这个ProcessRequestInternal(wr)又干什么了
}

第四步:ProcessRequestInternal(wr)查看:

private void ProcessRequestInternal(HttpWorkerRequest wr)
{
    HttpContext context;
    try
    {
        context = new HttpContext(wr, false);//是不是很熟悉这个东东啊
    }
    catch
    {
        wr.SendStatus(400, "Bad Request");//生成状态响应码是通过调用的wr对象生成的,因此我们知道Response.Write()方法发回状态码,是通过wr来操作的


        wr.SendKnownResponseHeader(12, "text/html; charset=utf-8");
        byte[] bytes = Encoding.ASCII.GetBytes("<html><body>Bad Request</body></html>");
        wr.SendResponseFromMemory(bytes, bytes.Length);
        wr.FlushResponse(true);
        wr.EndOfRequest();
        return;

    }
    wr.SetEndOfSendNotification(this._asyncEndOfSendCallback, context);
    Interlocked.Increment(ref this._activeRequestCount);
    HostingEnvironment.IncrementBusyCount();
    try
    {

        …………………//省略
        context.Response.InitResponseWriter();//上下文创建好后,就立即初始化Response.Writer
       IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(context);//在这里创建了HttpApplication,只不过是用IHttpHandler接收罢了
        if (applicationInstance == null)
        {
            throw new HttpException(SR.GetString("Unable_create_app_object"));
        }
        …………………//省略

    }
    catch (Exception exception)
    {
       …………………//省略

    }
}

第五步:InitResponseWriter();

internal void InitResponseWriter()
{
    if (this._httpWriter == null)
    {
        
this.
_httpWriter
= new
HttpWriter
(this);//如果当前的HttpWriter为空就立即new一个出来 this.
_writer
= this.
_httpWriter
;//并且将它赋给了_writer ,注意_writer 它的类型可不是HttpWriter了,而是TextWriter
    }
}

至此经过这么多的调用最终还是为了创建HttpContext和HttpApplication啊!

 

总结一下流程:

1、扩展程序 从 接口拿到请求报文
2、处理请求报文,封装生成wr
3、调用HttpRuntime方法中的pr方法(wr为参数),创建上下文对象HttpContext对象
4、初始化HttpResponse对象(目的是创建HtmlWrite)
5、创建HttpApplication对象(调用HttpApplication中的 pr方法,HttpContext为参数)(实    际上是 通过工厂创建HttpApplicationFactory.GetApplicationInstance(context))

 

未完,待续……………

作者: 樊林冲 发表于 2011-08-25 21:19 原文链接

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"