The little Thing before MVC series (3): httpruntime Analysis (bottom)
Article content
In other words, after a variety of complex internal processes that we don't know, unmanaged code formally begins calling Ispairuntime's ProcessRequest method (Ispairuntime inherits the Iispairuntime interface, which can interact with COM, and exposed the ProcessRequest interface method). As for why to call this method, the uncle is not very clear, can not find Microsoft-related information Oh. But the uncle is sure that this method is our official door to enter the httpruntime, and then see it.
Public intProcessRequest (IntPtrECBintIwrtype) {INTPTR phttpcompletion=IntPtr.Zero; if(Iwrtype = =worker_request_type_in_proc_version_2) {phttpcompletion=ECB; ECB=UNSAFENATIVEMETHODS.GETECB (phttpcompletion); } isapiworkerrequest WR=NULL; Try { BOOLUseoop = (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 domainHttpruntime.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 isThreadAbortException) {Thread.resetabort (); } //Important:if This thread was being aborted because of an appdomain.unload,//The CLR would 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 to notice is what is the parameter ecb,ecb of the IntPtr type of the method? The ECB is an unmanaged pointer, full name execution Control Block, which plays a very important role throughout the HTTP Request processing process, so let's briefly introduce an ECB.
The unmanaged environment ISAPI calls the Isapiruntime and needs to pass some necessary data, such as Isapiruntime to get the data from the server variable, to get the data returned to the server via post Mehod , and eventually the content of response is returned to the unmanaged environment ISAPI, which is then presented to the client user. In general, Isapiruntime cannot call ISAPI directly, so a call to it is implemented through an object pointer, which is the ECB,ECB implementation of access to an unmanaged environment ISAPI.
It is also important to note that the ISAPI call to Isapirutime is asynchronous, meaning that the ISAPI call Isapirutime returns immediately. This is primarily for performance and responsibility, because the ASP. NET application is inherently a multithreaded application, and for better responsiveness, asynchronous operations are the most effective solution. But there is a problem here, and we know that our call to the ASP. NET resource is essentially a request/response message Exchange Pattern, An asynchronous invocation often means that the ISAPI passes the request to isapiruntime and will not be able to get the response that Isapiruntime eventually generates, which is obviously unacceptable. While the ECB solves this problem, ISAPI passes its corresponding ECB pointer to it when calling Isapirutime's ProcessRequest method, Isapirutime not only returns the resulting response to the ISAPI, You can also call ISAPI through the ECB to get some of the data you need.
The 2nd bold code in the above code is a static method that executes Isapiworkerrequest createworkerrequest thus creating an Isapiworkerrequest object instance, Parameters are the ECB and the int parameter iwrtype representing the workerrequest type, let's take a look at the code for this method:
Internal StaticIsapiworkerrequest createworkerrequest (IntPtr ECB,BOOLUseoop) {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 { intVersion = Unsafenativemethods.ecbgetversion (ECB) >> -; 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=NewISAPIWorkerRequestInProcForIIS7 (ECB); } Else if(Version = =6) {WR=NewISAPIWorkerRequestInProcForIIS6 (ECB); } Else{WR=NewIsapiworkerrequestinproc (ECB); } } returnWR;}
Determine what type of workerrequest is created by judging the specifics of the ECB and type types (the above types of ispaiworkerrequest are inherited from HttpWorkerRequest). The code above shows that different versions of IIS are packaged differently, using their initialize method to initialize some basic information (such as ContentType, querystring length, filepath, etc.).
OK, continue to look at the ProcessRequest method of the bold code, the exciting moment came, see Httpruntime.processrequestnodemand (WR) This line of code? This is the only entry that really enters the ASP. NET Runtime pipeline, and the parameters passed are the Workerrequest object instances that were masked by the difference. Httpruntime.processrequestnodemand is finally reflected in calling the ProcessRequestInternal method, let's see what the method is doing.
Private voidprocessrequestinternal (HttpWorkerRequest wr) {//Construct the Context on HttpWorkerRequest, hook everything togetherHttpContext context; Try{ context = New HttpContext (WR, false / * initresponsewriter * /); } Catch { //If We fail to create the context for any reason, send a sure//The request is correctly closed (relates to VSUQFE3962)WR. Sendstatus ( -,"Bad Request"); Url Sendknownresponseheader (Httpworkerrequest.headercontenttype,"text/html; Charset=utf-8"); byte[] BODY = Encoding.ASCII.GetBytes (""); Url Sendresponsefrommemory (body, body. Length); Url Flushresponse (true); Url Endofrequest (); return; } WR. Setendofsendnotification (_asyncendofsendcallback, context); //Count Active RequestsInterlocked.Increment (ref_activerequestcount); Hostingenvironment.incrementbusycount (); Try { //First request Initialization Try{ensurefirstrequestinit (context); } Catch { //If We are handling a DEBUG request, ignore the firstrequestinit exception. //This allows the Httpdebughandler to execute, and lets the debugger attach to//The process (VSWhidbey 358135) if(!context. Request.isdebuggingrequest) {Throw; } } //Init response Writer (after we had config in first request Init)//no need for impersonation as it's handled in config systemcontext. Response.initresponsewriter (); //Get Application Instance IHttpHandler App = httpapplicationfactory.getapplicationinstance (context); if(App = =NULL) Throw NewHttpException (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 HandlerIHttpAsyncHandler Asynchandler=(IHttpAsyncHandler) app; Context. Asyncapphandler=Asynchandler; Asynchandler.beginprocessrequest (context, _handlercompletioncallback, context); } Else { //Synchronous Handlerapp. ProcessRequest (context); Finishrequest (context. Workerrequest, Context,NULL); } } Catch(Exception e) {context. Response.initresponsewriter (); Finishrequest (WR, context, E); }}
The first thing to see is the instantiation code of the HttpContext object in the Try/catch, which is where our long-awaited global HttpContext objects are generated, and the parameters are still instances of workerrequest, The HttpContext constructor code is as follows:
// ctor used in HttpRuntime Internal BOOL initresponsewriter) { = wr; Init ( Newthisnew )); if (initresponsewriter) _response. Initresponsewriter (); Perfcounters.incrementcounter (appperfcounter.requests_executing);}
We also saw 2 surprises of code, HttpRequest and HttpResponse instantiation, through the Workerrequest and the HttpContext object This parameter pass, will they need, the specific internal how to judge the operation assignment, We don't look closely, another 2 seconds to see the code inside the catch, there is the HTML code assembly logic that we often see on the Bad Request page, which means that if the HttpContext object creation fails, it will show us the bad Request page.
We continue with the more important code, which is another entrance, let's go into our familiar HttpApplication, the code is as follows:
// Get Application Instance = httpapplicationfactory.getapplicationinstance (context);
By HttpApplicationFactory's getapplicationinstance static method, we get familiar HttpApplication object instances, Because the HttpApplication object is inherited IHttpAsyncHandler, and IHttpAsyncHandler inherits from IHttpHandler, the above app type is IHttpHandler is not wrong. Continue to look at the following if (app is IHttpAsyncHandler) code, know that the app must walk the branch here, and then execute the call asynchandler.beginprocessrequest method.
At this point, HttpRuntime has formally played its irreplaceable role, formally through this object formally into the creation of HttpApplication objects and well-known HttpApplication life cycle.
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 recommendations
This article has been synchronized to the directory index: Thelittle Thing before MVC series
MVC before the point of the series of articles, including the original, translation, reprint and other types of articles, if it is useful to you, please recommend supporting a, to the power of the uncle writing.
Original link This article by Bean John Blog Backup expert remote One click release
What happened before MVC series (3): httpruntime Analysis (next) (reproduced)