HTTP: // Flier_ Road. Put LOGO .NET? ID = 1544105
For the .NET 1.1 Pre-compilation ASP.NET page Implementation Principle Analysis MS A large feature when publishing ASP.NET is different from Script language such as ASP and PHP, ASP.NET is actually a compilation web page Development environment. This makes the ASP.NET in terms of development and modification, while not affordable losses. Implement ASP.NET is similar to JSP, the engine is compiled into a class before using a page for the first time, automatically generates assembly and load execution. In the article "Embed an ASP.NET" in the WinForm program, we can understand that the ASP.NET engine can actually be used without the Web server calls such as IIS, which makes the manual pre-compilation ASP.NET page becomes may. In fact, this demand is generally existed. As early as the ASP era, there is a third-party product support to compile the ASP page into binary procedures to improve the efficiency and protection of code security, and will accompany the ASP.NET 2.0 published by Whidbey. Directly built-in the functionality of the precompiled ASP.NET page. In actually, some people have discussed the implementation of the simulated pre-compilation characteristics in ASP.NET 1.1, such as the following two articles pre-compiling ASP.NET Web Pages pre-compile aspx pages in .NET 1.1 Its ideas are basically Traverse all page files that need to be precompiled, and then trigger the ASP.NET engine's automatic pre-compilation mechanism by simulating the web page request. The benefits of doing this are completely simulated, there is no need to understand the principle of implementation of the ASP.NET engine; however, it will also be subject to many restrictions. If the precompiled result is opaque, you can't get it from the original ASP.NET page file, but also unable to make us Understand the implementation of pre-compilation characteristics from principle. Below I will be divided into three to four sections, briefly discuss the implementation of the ASP.NET automatic compilation mechanism, the implementation of the ASP.NET page file compilation and how to implement manual precompiled pages and corresponding distribution mechanisms in ASP.NET 1.1. [1] Automatic pre-compilation mechanism This section we will discuss in detail. NET 1.1, the ASP.NET engine implements the principle of automatic page pre-compilation. First, what we said is actually divided into four categories: 1.Web application files Global.asax 2.Web page file * .aspx 3. User custom control file * .ascx 4.Web service Document * .asmx web application files are optional for each web application, used to process events at first-level ASP.NET application, and will be precompiled as a child of a System.Web.httpApplication class Class; Web page file is a normal ASP.NET page, handling the event of a specific page, will be precompiled as subclasses for a System.Web.ui.page class; user-defined control files are special ASP.NET pages, Handling the control itself, will be precompiled as subclasses for a System.Web.ui.userControl class; the web service program file is a special page file that is not too the same as the top three, which is not discussed for the time being. Then, the compilation timing of the first three ASP.NET files is not exactly the same. The web application file is automatically compiled when this web application file is first used; the web page file is automatically compiled when this web page is first used, and it is actually called the httpruntime.processRequest function triggers pre-compilation; The control file is automatically compiled when he first is used by the web page. It is actually called the page.loadControl function to trigger pre-compilation.
After understanding these basic knowledge, let's analyze the automatic preparatory implementation mechanism. The httpruntime.processRequest function is a call initiator that handles the web page request. The pseudo code is as follows: The following is referenced:
Public static void httpruntime.processRequest (HTTPWORKERREQUEST WR)
{
// Check the current caller if there is an ASP.NET host (Host) permission
INTERNALSECURITYPERMISSIONS.ASPNETHOSTINGPERMISSIONLEVELMEDIUM.DEMAND ();
IF (WR == null)
{
Throw New Argumentnullexception ("Custom");
}
Requestqueue queue = httpruntime._theruntime._requestqueue;
IF (Queue! = NULL)
{
// Place the web page in the parameter into the request queue
/ / And get a page request from the queue using the FIFO policy
WR = queue.getRequestToExecute (WR);
}
IF (WR! = null)
{
// Update Performance Counter
HttPruntime.calculateWaitTimeandUpdatePerfcounter (WR);
// Real completed page request work
HTTPRUNTIME.PROCESSREQUESTNOW (WR);
}
}
The httpruntime.processRequestNow function calls the default HTTPRuntime instance's ProcessRequestinternal function to complete the actual page request, the pseudo code is as follows:
The following is quoted:
Internal static void httpruntime.processRequestNow (HTTPWORKERREQUEST WR)
{
HTTPRUNTIME._THERUNTIME.PROCESSREQUESTINAL (WR);
}
HttPruntime.ProcessRequestinternal function logic is slightly more complicated, which can be roughly divided into four parts.
First check whether the current HTTPRuntime instance is called for the first time, if it is the first call, it is initially initialized by the first REVESTINIT function;
Then call the httpResponse.initResponseWriter function initialization page request to return to the object httpWorkerRequest.Response;
Then call the httpapplicationFactory.GetApplicationInstance function to get the current web application instance;
Finally, use the web application instance to complete the actual page request work.
The pseudo code is as follows:
The following is quoted:
Private void httpruntime.processRequestinternal (HttpWorkerRequest WR)
{
// Construct HTTP call context object
HttpContext ctxt = new httpcontext (wr, 0);
// Set the transmission end asynchronous callback function
Wr.sendofsendNotification (this._asyncendofsendCallback, CTXT);
/ / Update Request Counter
Interlocked.Increment (& (this._activeRequestCount);
Try
{
/ / Check if the current HTTPRuntime instance is called for the first time
IF (this._beforefirstRequest)
{
LOCK (this)
{
//
Double-Checked mode Avoid redundant locks (this._beforefirstRequest)
{
THIS._FIRSTREQUESTARTTIME = DATETIME.UTCNOW;
this.firstRequestinit (CTXT); // Initialize the current HTTPRuntime runtime environment
THIS._BEFOREFIRSTREQUEST = FALSE;
}
}
}
/ / Play the role with higher privilege according to the configuration file settings
Ctxt.impersonation.start (True, False);
Try
{
/ / Initialize the return object of the page request
CTXT.Response.initResponsewriter ();
}
Finally
{
CTXT.ImPersonation.stop ();
}
/ / Get the current web application instance
IHTTPHANDLER HANDLER = httpApplicationFactory.getApplicationInstance (CTXT);
IF (Handler == Null)
{
Throw new httpexception (httpruntime.formatResourceString ("Unable_create_app_Object)));
}
// Use the web application instance to complete the actual page request work
IF ((Handler as IhttPasyncHandler)! = null)
{
IHTTPASYNCHANDAL AsyncHandler = ((ihttpasynchandler);
Ctxt.asyncapphandler = asynchandler;
// use asynchronous processing mechanism
AsyncHandler.BeginProcessRequest (CTXT, this._handlercompletioncallback, ctxt);
}
Else
{
Handler.ProcessRequest (CTXT);
This.finishRequest (CTXT.WorkerRequest, CTXT, NULL);
}
}
Catch (Exception E)
{
CTXT.Response.initResponsewriter ();
This.finishRequest (WR, CTXT, E);
}
}
In the httpruntime.processRequestinternal function, there are two parts involving file precompilation: First, when the current web application instance is obtained, it will automatically determine if the Web application file is pre-compiled according to the situation; the second is to complete the actual page request, will The precompiled behavior is triggered when a page is used for the first time.
Let's take a look at the processing of the web application file.
The httpApplicationFactory.GetApplicationInstance function is called in the HTTPRUNTime.ProcessRequestinternal function to get the current web application instance. System.Web.httpApplicationFactory is an internal class to implement management and cache for multiple web application instances. The GetApplicationInstance function returns an IHTTPHANDLER interface, providing the IHTTPHANDLER.PROCESSREQUEST function to process the web page file. The pseudo code is as follows:
The following is quoted:
Internal static httphandler httpapplicationfactory.getApplicationInstance (httpContext CTXT)
{
// Custom application
IF (httpapplicationfactory._customapplication! = null) {
Return httpapplicationfactory._customApplication;
}
// debugging request
IF (httpdebughandler.isDebuggingRequest (ctxt))
{
Return new httpdebughandler ();
}
// Judgment whether the current HTTPApplicationFactory instance is required
IF (! httpapplicationfactory._theapplicationfactory._INITED)
{
HTTPApplicationFactory Factory = httpapplicationfactory._theapplicationfactory;
LOCK (httpapplicationfactory._theapplicationfactory);
{
//
Double-Checked mode Avoid redundant locking
IF (! httpapplicationfactory._theapplicationfactory._INITED)
{
// Initialize the current HTTPAPPLICATIONFACTORY instance
HTTPApplicationFactory._TheApplicationFactory.init (CTXT);
HttpapplicationFactory._theapplicationfactory._INITED = true;
}
}
}
/ / Get a web application instance
Return httpapplicationfactory._theapplicationfactory.getnormalaLApplicationInstance (CTXT);
}
After processing special circumstances and possible instance initialization, call the httpApplicationFactory.GetNormalapplicationInstance function to complete the actual functionality of obtaining the web application instance, the pseudo code is as follows:
The following is quoted:
Private httpapplication httpapplicationfactory.getnormalaPplapplicationInstance (HTTPCONTEXT Context)
{
HTTPApplication App = NULL;
// Try to get from the existing web application instance queue
LOCK (this._freeelist)
{
IF (this._numfreeAppinstances> 0)
{
App = (httpapplication) THIS_FREELIST.POP ();
THIS._NUMFREEAPPINSTANCES -
}
}
IF (app == NULL)
{
/ / Construct a new web application instance
App = (httpapplication) System.Web.httPruntime.createnonpublicinstance (this._theapplicationtyty);
// Initialize the web application instance
App.initinternal (Context, this._state, this._eventhandlermethod);
}
Return APP;
}
The code constructs a new web application instance is simple. It is actually a simple packaging of the Activator.createInstance function, the pseudo code is as follows:
The following is quoted:
INTERNAL Static Object httpruntime.createnonpublicinstance (Type Type, Object [] ARGS)
{
Return Activator.createInstance (Type, BindingFlags.createInstance | BindingFlags.instance | BindingFlags.nonpublic | bindingflags.public, null, args, null;
}
Internal static object httpruntime.createnonpublicInstance (Type Type)
{
Return httpruntime.createnonpublicinstance (Type, NULL);
}
To this way, the web application instance is integrated, and then the initialization of the initinternal function can begin the actual page processing. The _TheApplicationType type of the HTTPApplicationFactory instance is the resulting Global.asax class after precompiled. The actual precompilation is completed in the httpapplicationfactory.init function, and the pseudo code is as follows:
The following is quoted:
Private void httpapplicationfactory.init (httpContext CTXT)
{
IF (httpapplicationfactory._customapplication! = null)
Return;
Using (httpcontextwrapper wrapper = new httpcontextwrapper (ctxt))
{
CTXT.ImPersonation.start (true, true);
Try
{
Try
{
THIS._APPFILENAME = httpapplicationfactory.getApplicationFile (CTXT);
This.CompileApplication (CTXT);
THIS.SETUPCHANGESMONITOR ();
}
Finally
{
CTXT.ImPersonation.stop ();
}
}
Catch (Object)
{
}
This.fireApplicationOnStart (CTXT);
}
}
The GetApplicationFile function returns the Global.asax file path in the physical directory; the CompileApplication function is based on whether this file exists. It is determined whether the precompiled and loaded type, or directly returns the default httpApplication type, the pseudo code is as follows:
The following is quoted:
INTERNAL STATIC STRING HTTPApplicationFactory.GetApplicationFile (HttpContext CTXT)
{
Return path.combine (ctxt.Request.PhysicalApplicationPath, "Global.asax");
}
Private void httpapplicationfactory.CompileApplication (httpContext CTXT)
{
IF (FileUtil.fileexists (this._appfilename))
{
ApplicationFileParser Parser;
/ / Get the compiled web application type
THIS._THEAPPLICATIONTYPE = ApplicationFileParser.getCompileDapplicationType (this._appfilename, context, out paser);
THIS._STATE = New httpapplicationState (Parser1.ApplicationObjects, Parser.SessionObjects; this._filedependencies = parse.sourcedependencies;
}
Else
{
THIS._THEApplicationType = TypeOf (httpapplication);
THIS._STATE = New httpapplicationState ();
}
This.ReflectonApplicationType ();
}
Analysis here we can find that the GetCompiLEPLICATIONTYPE function for internal type System.Web.ui.ApplicationFileParser is a place that actually performs WEB application compilation. But now we will stop, wait for the next analysis to analyze the compilation process. :)
Then we look at the processing of the web page file.
When analyzing the httpruntime.processRequestinternal function, we have learned that after obtaining the web application instance, the IHTTPASYNCHANDAL interface or IHTTPHANDLER interface of this instance is used to complete the actual page request. Whether or not there is a Global.asax file, the finally returned web application instance is an instance of an HTTPApplication class or its subclass, which implements the IHTTPASYNCHANDLER interface, supports asynchronous web page request work. The processed pseudo code for this interface is as follows:
The following is quoted:
Private void httpruntime.processRequestinternal (HttpWorkerRequest WR)
{
...
// Use the web application instance to complete the actual page request work
IF ((Handler as IhttPasyncHandler)! = null)
{
IHTTPASYNCHANDAL AsyncHandler = ((ihttpasynchandler);
Ctxt.asyncapphandler = asynchandler;
// use asynchronous processing mechanism
AsyncHandler.BeginProcessRequest (CTXT, this._handlercompletioncallback, ctxt);
}
Else
{
Handler.ProcessRequest (CTXT);
This.finishRequest (CTXT.WorkerRequest, CTXT, NULL);
}
...
}
The httpruntime.processRequestinternal function starts the page request work by calling the httpapplication.ihttpasynchandler.beginprocessRequest function. The httpapplication actually does not support the IHTTPHANDLER interface in synchronous form, and the pseudo code is as follows:
The following is quoted:
Void httpapplication.processRequest (System.Web.httpContext context)
{
Throw new httpexception (httpruntime.formatResourceString ("Sync_not_supported"));
}
Bool httpapplication.get_isreusable ()
{
Return True;
}
In the httpapplication.ihttpasynchandler.beginprocessRequest function, the very complex asynchronous calls are completed. This is not more than Luo Luo, and there is a chance to write articles to discuss the asynchronous operation in the ASP.NET. And its final call or use system.web.ui.pageParser to parse and compile the web page that needs to be processed. Finally, we look at the processing of the user-defined control file.
The LoadControl function of the page class is actually implemented in abstract class TemplateControl. The pseudo code is as follows:
The following is quoted:
Public Control LoadControl (String VirtualPath)
{
VirtualPath = urlpath.combine (base.templatesourcedirectory, virtualpath);
TYPE TYPE = UserControlParser.getCompileDuserControlType (VirtualPath, Null, Base.Context);
Return this.loadControl (Type1);
}
The actual user-defined control precompiled operation is done in the UserControlParser class.
At this section, in this section we have roughly understand the implementation principle of ASP.NET automatically pre-compile, and when doing pre-transcribes page files. The next section we will analyze ApplicationFileParser, PageParser, and UserControlParser to learn how ASP.NET is pre-compiled.