Previous MVC event series (4): detailed analysis of Http Pipeline (I)

Source: Internet
Author: User

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.

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.