Overview:
This article is based on the source code of ASP.NET 2.0 and conducts a brief analysis of the ASP.NET 2.0 runtime. I hope it can help you understand the request processing process and page compilation model in ASP.NET 2.0.
Keywords:
ASP.NET 2.0 runtime, principles, request processing, page compilation, ASP.NET 2.0 HTTP Runtime
main classes:
System.Web.HttpRuntime
System.Web.HttpApplicationFactory
System.Web.HttpApplication
System.Web.Compilation.BuildManager
System.Web.Compilation.ApplicationBuildProvider
System.Web.Compilation.BuildProvidersCompiler
System.Web.UI.PageHandlerFactory
Brief flow chart of request processing:
Reading suggestions:
Use the Reflector tool to view the source code of ASP.NET 2.0 while reading.
analyze:
When we initiate a request to an asp.net page on the ASP.NET 2.0 website through the browser, IIS first receives the request on the server side. When IIS sees that it is an asp.net page, I feel very happy because this request does not need to be processed by it. , just leave it to ASP.NET ISAPI. The work of ASP.NET ISAPI is also relatively easy. Its main task is to arrange for aspnet_wp.exe to process requests and monitor the execution of the aspnet_wp.exe process. If the aspnet_wp.exe process is too tired and cannot complete the task well, ASP.NET ISAPI will lay him off and replace him with a new aspnet_wp.exe to handle the work.
The main task of aspnet_wp.exe is to hand over requests to a series of managed objects called HTTP pipelines. If ASP.NET ISAPI is compared to a sales manager, then aspnet_wp.exe is the production manager, and the HTTP pipeline is the production pipeline. The team responsible for the assembly line is HttpRuntime. The production manager aspnet_wp.exe will hand over the order (HTTP request) to the HttpRuntime team member ProcessRequest (HttpWorkerRequest wr). HttpRuntime will eventually be produced on the assembly line by ProcessRequestInternal (HttpWorkerRequest wr) according to the internal division of labor. , so ProcessRequestInternal(HttpWorkerRequest wr) is the focus of our analysis.
The main work of ProcessRequestInternal is:
1. Create an HttpContext instance.
2. Initialize the first request (EnsureFirstRequestInit).
a) Perform some initialization work in EnsureFirstRequestInit by calling System.Web.HttpRuntime.FirstRequestInit, such as reading the Web.Config configuration into RuntimeConfig and loading all dll files from the bin directory.
3. Create an HttpWriter instance.
4. Create an HttpApplication instance by calling HttpApplicationFactory.GetApplicationInstance.
There are three key methods in HttpApplicationFactory.GetApplicationInstance:
HttpApplicationFactory._theApplicationFactory.EnsureInited();
HttpApplicationFactory._theApplicationFactory.EnsureAppStartCalled(context);
HttpApplicationFactory._theApplicationFactory.GetNormalApplicationInstance(context);
Let’s analyze these three methods one by one:
1) HttpApplicationFactory._theApplicationFactory.EnsureInited();
This method checks whether HttpApplicationFactory has been initialized. If not, it is initialized through HttpApplicationFactory.Init().
In Init(), first obtain the full path of the global.asax file, and then call CompileApplication() to compile global.asax.
How is compilation performed?
The compilation work is completed by BuildManager. BuildManager first gets the GlobalAsaxType (that is, HttpApplication), and then calls BuildManager.GetGlobalAsaxBuildResult() =》GetGlobalAsaxBuildResultInternal() =》EnsureTopLevelFilesCompiled() for compilation.
In EnsureTopLevelFilesCompiled, CompilationStage.TopLevelFiles is compiled first, and the files in the following three directories are compiled:
a. CompileResourcesDirectory();
Compile the App_GlobalResources directory.
b. CompileWebRefDirectory();
Compile the App_WebReferences directory.
c. CompileCodeDirectories();
Compile the App_Code directory.
Then compile CompilationStage.GlobalAsax, compile global.asax, and method call: CompileGlobalAsax()=》ApplicationBuildProvider.GetGlobalAsaxBuildResult(BuildManager.IsPrecompiledApp).
The specific compilation in GetGlobalAsaxBuildResult is completed by ApplicationBuildProvider and BuildProvidersCompiler.
BuildProvidersCompiler.PerformBuild(); performs compilation work.
ApplicationBuildProvider.GetBuildResult gets the compiled result.
After successful compilation, a dll file similar to App_global.asax.mlgx7n2v.dll will be generated in the corresponding directory of C:WINDOWSMicrosoft.NETFrameworkv2.0.50727Temporary ASP.NET Files.
The compiled class is named ASP.global_asax and inherits from HttpApplication.
Note: If there is no Global.asax file in the Web directory, files such as App_global.asax.mlgx7n2v.dll will not be compiled and generated.
2) HttpApplicationFactory._theApplicationFactory.EnsureAppStartCalled(context);
Create a specific HttpApplication instance, trigger the ApplicationOnStart event, and execute the Application_Start(object sender, EventArgs e) method in ASP.global_asax. The HttpApplication instance created here is recycled after processing the event.
3) HttpApplicationFactory._theApplicationFactory.GetNormalApplicationInstance(context);
This method creates an HttpApplication instance and initializes it (calling the System.Web.HttpApplication.InitInternal() method).
Creating an HttpApplication instance is based on the actual _theApplicationType. If there is no global.asa file in the Web directory, that is to say, there is no dynamic compilation to generate the ASP.global_asax type, then instantiate HttpApplication directly. If the ASP.global_asax type is created, instantiate ASP.global_asa.
After creating the HttpApplication instance, call the InitInternal method of the instance.
The InitInternal method is also the method we focus on. The main functions of this method are as follows:
1. InitModules(): Create corresponding HttpModules according to the settings of Web.Config.
2. HookupEventHandlersForAppplicationAndModules: Based on the event that occurs, call the corresponding event processing function in the HttpApplication instance.
3. Create many instances of classes that implement the IExecutionStep interface and add them to _execSteps of the current HttpApplication instance, and wait for callback execution. From here we can see that HttpApplication processes requests in an asynchronous manner, and many processing tasks for requests are put into _execStep to wait for the callback to be executed.
The main processing work in _execStep is as follows:
1) Perform a security check on the requested path and prohibit illegal path access (ValidatePathExecutionStep).
2) If UrlMappings is set, perform RewritePath(UrlMappingsExecutionStep).
3) Execute event processing functions, such as: BeginRequest, AuthenticateRequest, etc.
4) Obtain the HttpHandler that handles the current request. The runtime compilation of the ASP.NET page is also performed here. (MapHandlerExecutionStep)
This processing is done by calling the System.Web.HttpApplication.MapHttpHandler method.
In MapHttpHandler, first obtain the corresponding type that implements IHttpHandlerFactory from web.config according to the accessed address. For asp.net pages, the default is PageHanlderFactory. Then create a PageHanlderFactory instance, call GetHandlerHelper, call BuildManager.CreateInstanceFromVirtualPath in GetHandlerHelper to compile and create an instance of the currently requested ASP.NET page (if it has been compiled, load it directly from the cache).
CreateInstanceFromVirtualPath passes the compilation task to BuildManager. CompileWebFile() after several method calls. CompileWebFile gets the corresponding BuildProvider from web.config. For .aspx files, the corresponding BuildProvider is PageBuildProvider. How PageBuildProvider compiles pages will not be further analyzed here. If you are interested, you can further study the source code of ASP.NET 2.0.
5) Call the .ProcessRequest method of the corresponding HttpHandler to process the request (if it is asynchronous, call BeginProcessReques). (CallHandlerExecutionStep)
6) Write the response content into Filter. (CallFilterExecutionStep)
5. Call BeginProcessRequest of the HttpApplication instance to process the request asynchronously.
Many of the things that happen in _execSteps mentioned above are executed after HttpRuntime calls HttpApplication BeginProcessRequest and then calls ResumeSteps in BeginProcessRequest.
The ASP.NET 2.0 runtime is a very complex, difficult to understand and important part of ASP.NET 2.0. The study of the ASP.NET 2.0 runtime source code will help us deepen our understanding of the principles of ASP.NET 2.0 and will give us Developing ASP.NET 2.0 applications brings a lot of help. This article is my first time learning the ASP.NET 2.0 runtime. It was written to help me better understand the ASP.NET 2.0 runtime. You are welcome to criticize and make suggestions on the content of the article.
I feel that writing articles can not only improve one's writing skills and facilitate communication, but also through writing articles, one can clarify one's own ideas, promote in-depth thinking, and deepen one's understanding of technology. Developers can take some time away from coding. Writing some technical articles is still very helpful to improve yourself.