Previous MVC event series (3): HttpRuntime detailed analysis (II)

Source: Internet
Author: User

Article content

After a variety of complex internal processes that we don't know, the unmanaged code officially began to call the ProcessRequest method of ISPAIRuntime (ISPAIRuntime inherits the IISPAIRuntime interface, which can interact with COM, and exposes the ProcessRequest interface method ). As for why I want to call this method, I am not very clear about it. I cannot find any information related to Microsoft. But uncle is sure that this method is the official entrance to HttpRuntime. Let's take a look.

public int ProcessRequest(IntPtr ecb, int iWRType) {    IntPtr pHttpCompletion = IntPtr.Zero;    if (iWRType == WORKER_REQUEST_TYPE_IN_PROC_VERSION_2) {        pHttpCompletion = ecb;        ecb = UnsafeNativeMethods.GetEcb(pHttpCompletion);    }    ISAPIWorkerRequest wr = null;    try {        bool useOOP = (iWRType == WORKER_REQUEST_TYPE_OOP);        wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP);        wr.Initialize();         // check if app path matches (need to restart app domain?)        String wrPath = wr.GetAppPathTranslated();        String adPath = HttpRuntime.AppDomainAppPathInternal;         if (adPath == null ||            StringUtil.EqualsIgnoreCase(wrPath, adPath)) {             HttpRuntime.ProcessRequestNoDemand(wr);            return 0;        }        else {            // need to restart app domain            HttpRuntime.ShutdownAppDomain(ApplicationShutdownReason.PhysicalApplicationPathChanged,                                            SR.GetString(SR.Hosting_Phys_Path_Changed,                                                                            adPath,                                                                            wrPath));            return 1;        }    }    catch(Exception e) {        try {            WebBaseEvent.RaiseRuntimeError(e, this);        } catch {}         // Have we called HSE_REQ_DONE_WITH_SESSION?  If so, don't re-throw.        if (wr != null && wr.Ecb == IntPtr.Zero) {            if (pHttpCompletion != IntPtr.Zero) {                UnsafeNativeMethods.SetDoneWithSessionCalled(pHttpCompletion);            }            // if this is a thread abort exception, cancel the abort            if (e is ThreadAbortException) {                Thread.ResetAbort();            }            // IMPORTANT: if this thread is being aborted because of an AppDomain.Unload,            // the CLR will still throw an AppDomainUnloadedException. The native caller            // must special case COR_E_APPDOMAINUNLOADED(0x80131014) and not            // call HSE_REQ_DONE_WITH_SESSION more than once.            return 0;        }         // re-throw if we have not called HSE_REQ_DONE_WITH_SESSION        throw;    }}

 

The first thing I noticed was the IntPtr type parameter ecb of this method. What is ecb? Ecb is an unmanaged pointer and its full name is Execution Control Block. It plays an important role in the whole Http Request Processing process. We will introduce a ECB briefly.

 

In an unmanaged environment, when ISAPI calls ISAPIRuntime, it needs to pass some necessary data. For example, ISAPIRuntime needs to get the data of Server Variable and get the data transmitted from Server through Post Mehod; and finally return the Response content to the unmanaged ISAPI, and then present it to the Client user. Generally, ISAPIRuntime cannot directly call ISAPI. Therefore, an object pointer is used to call ISAPI. This object is ECB, which enables access to the ISAPI in an unmanaged environment.

 

In addition, ISAPI calls to ISAPIRutime are asynchronous, that is, ISAPI returns immediately after ISAPIRutime is called. This is mainly due to Performance and Responsibility, because ASP. NET Application is inherently a multi-threaded Application. In order to have better response capabilities, asynchronous operations are the most effective solution. However, there will be a problem here. We know that we use ASP. NET resource calls are essentially a Request/Response Message Exchange Pattern. asynchronous calls often mean that ISAPI passes the Request to ISAPIRuntime and cannot get the final Response generated by ISAPIRuntime, this is obviously unacceptable. The ECB solves this problem. When ISAPI calls the ISAPIRutime ProcessRequest method, it will pass its own corresponding ECB pointer to it. ISAPIRutime can not only return the final Response to ISAPI, the ECB can also call ISAPI to obtain required data.

 

In the above Code, the 2nd bold code is to execute the static method CreateWorkerRequest of ISAPIWorkerRequest to create an ISAPIWorkerRequest object instance. The parameters are ecb and iWRType, the int parameter representing the WorkerRequest type, respectively, let's take a look at the code of this method:

internal static ISAPIWorkerRequest CreateWorkerRequest(IntPtr ecb, bool useOOP) {     ISAPIWorkerRequest wr = null;    if (useOOP) {        EtwTrace.TraceEnableCheck(EtwTraceConfigType.DOWNLEVEL, IntPtr.Zero);         if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_APPDOMAIN_ENTER, ecb, Thread.GetDomain().FriendlyName, null, false);         wr = new ISAPIWorkerRequestOutOfProc(ecb);    }    else {        int version = UnsafeNativeMethods.EcbGetVersion(ecb) >> 16;         if (version >= 7) {            EtwTrace.TraceEnableCheck(EtwTraceConfigType.IIS7_ISAPI, ecb);        }        else {            EtwTrace.TraceEnableCheck(EtwTraceConfigType.DOWNLEVEL, IntPtr.Zero);        }         if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_APPDOMAIN_ENTER, ecb, Thread.GetDomain().FriendlyName, null, true);         if (version >= 7) {            wr = new ISAPIWorkerRequestInProcForIIS7(ecb);        }        else if (version == 6) {            wr = new ISAPIWorkerRequestInProcForIIS6(ecb);        }        else {            wr = new ISAPIWorkerRequestInProc(ecb);        }    }    return wr;}

 

Determine the type of WorkerRequest to be created by determining the specific content of the ecb and type types (the above type of iseries WorkerRequest inherits from HttpWorkerRequest ), the code above shows that different versions of IIS are packaged and some basic information (such as contentType and querystring length) is initialized through the Initialize method, filepath ).

 

OK. Continue to read the rough code of the ProcessRequest method. The exciting time is coming. Have you seen the code of HttpRuntime. ProcessRequestNoDemand (wr? This is the only entry that truly enters ASP. NET Runtime Pipeline. The passed parameter is the WorkerRequest object instance shielded from differentiation. HttpRuntime. ProcessRequestNoDemand is ultimately reflected in calling the ProcessRequestInternal method. Let's take a look at what the method is doing.

private void ProcessRequestInternal(HttpWorkerRequest wr) {    // Construct the Context on HttpWorkerRequest, hook everything together    HttpContext context;     try {        context = new HttpContext(wr, false /* initResponseWriter */);    }    catch {        // If we fail to create the context for any reason, send back a 400 to make sure        // the request is correctly closed (relates to VSUQFE3962)        wr.SendStatus(400, "Bad Request");        wr.SendKnownResponseHeader(HttpWorkerRequest.HeaderContentType, "text/html; charset=utf-8");        byte[] body = Encoding.ASCII.GetBytes("        IHttpHandler app = HttpApplicationFactory.GetApplicationInstance(context);        if (app == null)            throw new HttpException(SR.GetString(SR.Unable_create_app_object));         if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_START_HANDLER, context.WorkerRequest, app.GetType().FullName, "Start");        if (app is IHttpAsyncHandler) {            // asynchronous handler            IHttpAsyncHandler asyncHandler = (IHttpAsyncHandler)app;            context.AsyncAppHandler = asyncHandler;            asyncHandler.BeginProcessRequest(context, _handlerCompletionCallback, context);        }        else {            // synchronous handler            app.ProcessRequest(context);            FinishRequest(context.WorkerRequest, context, null);        }    }    catch (Exception e) {        context.Response.InitResponseWriter();        FinishRequest(wr, context, e);    }}

 

First, we can see the instantiation code of the HttpContext object in try/catch. This is the place where the long-awaited global HttpContext object is generated. The parameter is still an instance of WorkerRequest, the HttpContext constructor code is as follows:

// ctor used in HttpRuntimeinternal HttpContext(HttpWorkerRequest wr, bool initResponseWriter) {    _wr = wr;    Init(new HttpRequest(wr, this), new HttpResponse(wr, this));     if (initResponseWriter)        _response.InitResponseWriter();     PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_EXECUTING);}

 

We can see two more surprising codes: The instantiation of HttpRequest and HttpResponse. By passing the WorkerRequest and the this parameter of the HttpContext object, we will get the information they need, how does one determine the operation assignment internally? We will not take a closer look. In addition, we will take another two seconds to look at the code in catch, we often see the HTML code assembly logic displayed on the Bad Request page. That is to say, if the HttpContext object fails to be created, the Bad Request page will be displayed to us.

 

We continue to use more important code, which is another entry point. Let's enter the familiar HttpApplication. The Code is as follows:

// Get application instanceIHttpHandler app = HttpApplicationFactory.GetApplicationInstance(context);

 

Use the GetApplicationInstance static method of HttpApplicationFactory to obtain the familiar HttpApplication object instance. Because the HttpApplication object inherits IHttpAsyncHandler, And the IHttpAsyncHandler inherits IHttpHandler, therefore, the above app Type is IHttpHandler. Continue to read the later if (app is IHttpAsyncHandler) code, and you will know that the app must go through the branch here, and then execute the asyncHandler. BeginProcessRequest method.

 

Now, HttpRuntime has played an irreplaceable role, and officially enters the creation of the HttpApplication object and the lifecycle of the well-known HttpApplication.

References:

Http://www.ixwebhosting.mobi/asp-net-process-model-of-the-two-asp-net-http-runtime-pipeline-the-articles/

Http://dotnetslackers.com/articles/iis/ASPNETInternalsIISAndTheProcessModel2.aspx

Http://msdn.microsoft.com/en-us/library/bb470252.aspx

Http://msdn.microsoft.com/en-us/library/Aa479328.aspx

Http://learn.iis.net/page.aspx/101/introduction-to-iis-architecture/

Http://www.cnblogs.com/zhaoyang/archive/2011/11/16/2251200.html

Http://www.dotnetfunda.com/articles/article821-beginners-guide-how-iis-process-aspnet-request.aspx

Synchronization and recommendation

This article has been synchronized to the Directory Index: the previous MVC Series

The previous MVC series of articles, including original articles, translations, reposts, and other types of articles. If they are useful to you, we recommend that you support them to give uncle the motivation to write.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.