Article content
Continue to the content in the previous chapter, obtain the instance through the GetApplicationInstance static method of HttpApplicationFactory, and then execute the BeginProcessRequest method of the instance to execute the remaining Http Pipeline operations. The Code is as follows:
// Get application instance IHttpHandler app = HttpApplicationFactory.GetApplicationInstance(context);
So what did the GetApplicationInstance method do? Is it just a new object? This should not be the case. Let's take a look at the source code of the static GetApplicationInstance method of the HttpApplicationFactory class:
internal static IHttpHandler GetApplicationInstance(HttpContext context) { if (_customApplication != null) return _customApplication; // Check to see if it's a debug auto-attach request if (context.Request.IsDebuggingRequest) return new HttpDebugHandler(); _theApplicationFactory.EnsureInited(); _theApplicationFactory.EnsureAppStartCalled(context); return _theApplicationFactory.GetNormalApplicationInstance(context); }
There are three lines of code that I have marked as bold. Before explaining the specific functions of each line of code, let's see where the _ theApplicationFactory object instance comes from, by viewing the declaration code of this field, we can see that it is a singleton implementation.
// the only instance of application factoryprivate static HttpApplicationFactory _theApplicationFactory = new HttpApplicationFactory();
The first line of bold code is execution. The instance's EnsureInited method will call the Init method through the lock method (the benefit is naturally Needless to say). The Code is as follows:
private void EnsureInited() { if (!_inited) { lock (this) { if (!_inited) { Init(); _inited = true; } } }}
By looking for the code of the Init method and the details in the following two lines of code, we can know that the two lines of code are mainly obtained from global. asax and then compiled.
_appFilename = GetApplicationFile(); CompileApplication();
Therefore, the HttpApplicationFactory. _ theApplicationFactory. EnsureInited () method first checks whether the HttpApplicationFactory is initialized. If not, it uses HttpApplicationFactory. Init () for initialization. In Init (), obtain the complete path of the global. asax file, and then call CompileApplication () to compile global. asax.
The EnsureAppStartCalled method in the bold line 2nd will call the following private method FireApplicationOnStart. The Code is as follows:
private void FireApplicationOnStart(HttpContext context) { if (_onStartMethod != null) { HttpApplication app = GetSpecialApplicationInstance(); app.ProcessSpecialRequest( context, _onStartMethod, _onStartParamCount, this, EventArgs.Empty, null); RecycleSpecialApplicationInstance(app); }}
The Code shows that HttpApplicationFactory. _ theApplicationFactory. EnsureAppStartCalled (context) creates a specific HttpApplication instance, triggers the ApplicationOnStart event, and executes the Application_Start (object sender, EventArgs e) method in ASP. global_asax. Then it will be recycled immediately after the event is processed, because the system only needs to be initialized once, but some special things will be done for IIS7 in GetSpecialApplicationInstance, which we will discuss later.
The bold code in line 3rd is the focus of our attention here. The Code in its method is as follows:
private HttpApplication GetNormalApplicationInstance(HttpContext context) { HttpApplication app = null; lock (_freeList) { if (_numFreeAppInstances > 0) { app = (HttpApplication)_freeList.Pop(); _numFreeAppInstances--; if (_numFreeAppInstances < _minFreeAppInstances) { _minFreeAppInstances = _numFreeAppInstances; } } } if (app == null) { // If ran out of instances, create a new one app = (HttpApplication)HttpRuntime.CreateNonPublicInstance(_theApplicationType); using (new ApplicationImpersonationContext()) { app.InitInternal(context, _state, _eventHandlerMethods); } } return app; }
If there is an idle HttpApplication instance, it will be used directly. If no, it will be created. Then, the InitInternal method will be called to initialize the relevant content, and the HttpApplication instance will be returned.
Let's take a look at what is done in InitInternal, the core method of HttpApplication. There are a lot of code first, but it is worth it:
internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers) { Debug.Assert(context != null, "context != null"); // Remember state _state = state; PerfCounters.IncrementCounter(AppPerfCounter.PIPELINES); try { try { // Remember context for config lookups _initContext = context; _initContext.ApplicationInstance = this; // Set config path to be application path for the application initialization context.ConfigurationPath = context.Request.ApplicationPathObject; // keep HttpContext.Current working while running user code using (new DisposableHttpContextWrapper(context)) { // Build module list from config if (HttpRuntime.UseIntegratedPipeline) { Debug.Assert(_moduleConfigInfo != null, "_moduleConfigInfo != null"); Debug.Assert(_moduleConfigInfo.Count >= 0, "_moduleConfigInfo.Count >= 0"); try { context.HideRequestResponse = true; _hideRequestResponse = true; InitIntegratedModules(); } finally { context.HideRequestResponse = false; _hideRequestResponse = false; } } else { InitModules(); // this is used exclusively for integrated mode Debug.Assert(null == _moduleContainers, "null == _moduleContainers"); } // Hookup event handlers via reflection if (handlers != null) HookupEventHandlersForApplicationAndModules(handlers); // Initialization of the derived class _context = context; if (HttpRuntime.UseIntegratedPipeline && _context != null) { _context.HideRequestResponse = true; } _hideRequestResponse = true; try { Init(); } catch (Exception e) { RecordError(e); } } if (HttpRuntime.UseIntegratedPipeline && _context != null) { _context.HideRequestResponse = false; } _hideRequestResponse = false; _context = null; _resumeStepsWaitCallback= new WaitCallback(this.ResumeStepsWaitCallback); // Construct the execution steps array if (HttpRuntime.UseIntegratedPipeline) { _stepManager = new PipelineStepManager(this); } else { _stepManager = new ApplicationStepManager(this); } _stepManager.BuildSteps(_resumeStepsWaitCallback); } finally { _initInternalCompleted = true; // Reset config path context.ConfigurationPath = null; // don't hold on to the context _initContext.ApplicationInstance = null; _initContext = null; } } catch { // Protect against exception filters throw; }}
This code has two main functions: one is to initialize the familiar HttpModules, and the other is to execute the processing functions of more than 20 lifecycle events through BuildSteps (this part of content, we will explain Http Pipeline in details in the next chapter ). Through the code above, we can see that each function has a special judgment to determine whether IIS is an IIS7 integration mode. If so, there are special steps. If not, the general steps are taken, the direct difference between the two is that IIS7 will read from the Modules configured on the website when initializing HttpModules (because IIS7 pre-loads CLR and a large number of Modules) and BuildSteps, the IIS7 integration mode adopts its own special process (loading HttpModules on the server ).
Let's take a look at the code. The main functions of the InitInternal method are as follows:
So far, we have not explained the Handler-related Code except for more than 20 periodic events. Other Code related to HttpApplication that is helpful to us is almost clear. For more than 20 periodic events and Handler execution, we will explain in detail in the next section.
References:
Http://msdn.microsoft.com/en-us/magazine/cc188942.aspx
Http://msdn.microsoft.com/en-us/library/bb470252.aspx
Http://www.cnblogs.com/zhaoyang/archive/2011/11/16/2251200.html
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.