MVC以前-ASP.NET初始化流程分析1

理論的解說通常都是枯燥的,研究一個代碼框架更是如此,彷佛除了對大量的源碼加以解釋以外無話可說,可是這又是不可缺乏的,不然應用這樣的框架起來總有不放心之感,總有很多的坑要踩。更進一步講,一個好的框架應該給它的使用者足夠的擴展空間(尤爲是像MVC這樣的基礎框架),對框架自己沒有很好的把握則對於框架的擴展彷佛就只能尋找別人的「成功」經驗了,然而生搬硬套歷來不是解決問題的好方法,合理運用他人經驗與創造性的解決方案都離不開對框架的深刻理解,從這方面來講代碼分析其實強於抽象的說明,由於代碼的邏輯是肯定的,代碼的語言說服力其實強於書面語言(固然是指編寫良好的代碼)。固然對於代碼以外的討論也是很是必要甚至更加劇要的,好比探討框架設計的思路和模式,框架應用的相關實踐乃至對框架的擴展等等。此一系列文章都是基於Asp.net Mvc框架的源碼(包括Asp.net的一部分)對框架的基本設計與實現做出分析,另外參考了本身的一些項目以及當前一些優秀的開源項目(好比orchard)來討論框架的應用與擴展。web

Asp.net Mvc是當前使用比較多的web框架,也是比較先進的框架,目前.net的大部分源碼都已經開放,這大大方便了咱們對Asp.net Mvc的分析,下面就從Http請求進入Mvc框架處理以前的基本流程提及。api

因爲各IIS版本和工做模式(經典模式、集成模式)的不一樣,Http請求進入Asp.net的處理通道並不同,這裏不去細究裏面的細節,就從建立應用程序域開始:app

AppManagerAppDomainFactory分析

注:AppDomainFactory及AppManagerAppDomainFactory類在System.Web.Hosting中實現框架

在建立Appdomain時會調用IAppDomainFactory接口,該接口的實現以下:dom

 public sealed class AppDomainFactory : IAppDomainFactory {
        private AppManagerAppDomainFactory _realFactory; public AppDomainFactory() { _realFactory = new AppManagerAppDomainFactory(); } public Object Create(String module, String typeName, String appId, String appPath,String strUrlOfAppOrigin, int iZone) { return _realFactory.Create(appId, appPath); } }

該實現會調用AppManagerAppDomainFactory完成實際的建立過程。ui

  public sealed class AppManagerAppDomainFactory : IAppManagerAppDomainFactory {
        private ApplicationManager _appManager; public AppManagerAppDomainFactory() { _appManager = ApplicationManager.GetApplicationManager(); _appManager.Open(); } public Object Create(String appId, String appPath) { try { if (appPath[0] == '.') { System.IO.FileInfo file = new System.IO.FileInfo(appPath); appPath = file.FullName; } if (!StringUtil.StringEndsWith(appPath, '\\')) { appPath = appPath + "\\"; } ISAPIRuntime isapiRuntime = (ISAPIRuntime)_appManager.CreateObjectInternal(appId, typeof(ISAPIRuntime), appHost,false, null); isapiRuntime.StartProcessing(); return new ObjectHandle(isapiRuntime); } catch (Exception e) { Debug.Trace("internal", "AppDomainFactory::Create failed with " + e.GetType().FullName + ": " + e.Message + "\r\n" + e.StackTrace); throw; } } }

代碼的主要做用,就是經過ApplicationManager的CreateObjectInternal建立AppDomain,建立HostingEnvironment等,最終獲取ISAPIRuntime的實例,而後讓非託管代碼調用。this

ApplicationManager分析

注:ApplicationManager類在System.Web.Hosting中實現spa

首先看ApplicationManager類中的靜態的建立ApplicationManager對象的方法:.net

public static ApplicationManager GetApplicationManager() {
        if (_theAppManager == null) { lock (_applicationManagerStaticLock) { if (_theAppManager == null) { if (HostingEnvironment.IsHosted) _theAppManager = HostingEnvironment.GetApplicationManager(); if (_theAppManager == null) _theAppManager = new ApplicationManager(); } } } return _theAppManager; }

若是HostingEnvironment已經建立則能夠直接返回當前HostingEnvironment設置的ApplicationManager,若是沒有則建立新的ApplicationManager實例。設計

而後看ApplicationManager的CreateObjectInternal方法:

internal IRegisteredObject CreateObjectInternal(String appId, Type type, IApplicationHost appHost, bool failIfExists, HostingEnvironmentParameters hostingParameters) {
        if (!typeof(IRegisteredObject).IsAssignableFrom(type)) throw new ArgumentException(SR.GetString(SR.Not_IRegisteredObject, type.FullName), "type"); HostingEnvironment env = GetAppDomainWithHostingEnvironment(appId, appHost, hostingParameters); ObjectHandle h = env.CreateWellKnownObjectInstance(type.AssemblyQualifiedName, failIfExists); return (h != null) ? h.Unwrap() as IRegisteredObject : null; }

首先要先取得HostingEnvironment的實例,而後經過該實例的CreateWellKnownObjectInstance方法返回上述Create方法須要的ISAPIRuntime的實例。先來看如何獲取HostingEnvironment實例的方法GetAppDomainWithHostingEnvironment。

private HostingEnvironment GetAppDomainWithHostingEnvironment(String appId, IApplicationHost appHost, HostingEnvironmentParameters hostingParameters) {
        LockableAppDomainContext ac = GetLockableAppDomainContext (appId); lock (ac) { HostingEnvironment env = ac.HostEnv; if (env != null) { try { env.IsUnloaded(); } catch(AppDomainUnloadedException) { env = null; } } if (env == null) { env = CreateAppDomainWithHostingEnvironmentAndReportErrors(appId, appHost, hostingParameters); ac.HostEnv = env; Interlocked.Increment(ref _accessibleHostingEnvCount); } return env; } }

首先會檢查字典是否會有已經存在的HostingEnvironment實例,若是有就返回,沒有就會建立一個新的並保存到字典中,查看相關代碼發現最終會調用ApplicationManager的私有方法CreateAppDomainWithHostingEnvironment建立AppDomain和HostingEnvironment。

  private HostingEnvironment CreateAppDomainWithHostingEnvironment(String appId, IApplicationHost appHost, HostingEnvironmentParameters hostingParameters)
  {
       ……
       appDomain = AppDomain.CreateDomain(domainId,GetDefaultDomainIdentity(),setup); …… Type hostType = typeof(HostingEnvironment); String module = hostType.Module.Assembly.FullName; String typeName = hostType.FullName; ObjectHandle h = null; …… try { h = Activator.CreateInstance(appDomain, module, typeName); } …… HostingEnvironment env = (h != null) ? h.Unwrap() as HostingEnvironment : null; if (env == null) throw new SystemException(SR.GetString(SR.Cannot_create_HostEnv)); IConfigMapPathFactory configMapPathFactory = appHost.GetConfigMapPathFactory(); if (appDomainStartupConfigurationException == null) { env.Initialize(this, appHost, configMapPathFactory, hostingParameters, policyLevel); } else { env.Initialize(this, appHost, configMapPathFactory, hostingParameters, policyLevel, appDomainStartupConfigurationException); } return env; }

能夠看到代碼建立了AppDomain和HostingEnvironment實例,建立HostingEnvironment實例之後,緊接着會調用其Initialize方法來進行初始化,而後返回對象實例。

HostingEnvironment分析

Initialize初始化方法,注意該方法的第一個參數是this,也就是ApplicationManager實例自身,這樣會在HostingEnvironment中設置ApplicationManager,於是初始化以後能夠經過HostingEnvironment獲取ApplicationManager 。Initialize方法調用HttpRuntime的靜態方法,進行一些初始化工做(其中會調用BuildManager的InitializeBuildManager方法進行初始化另一些工做,其中包括編譯App_Code目錄下全部的.NET源代碼)。最後若是HostingEnvironment初始化失敗時會設置hostingInitFailed爲true。

internal void Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory, HostingEnvironmentParameters hostingParameters, PolicyLevel policyLevel, Exception appDomainCreationException)
{
    ……
    _appManager = appManager; …… HttpRuntime.InitializeHostingFeatures(hostingFlags,policyLevel,appDomainCreationException); …… catch (Exception e) { _hostingInitFailed = true; } }

建立HostingEnvironment後,會調用其方法CreateWellKnownObjectInstance建立ISAPIRuntime。建立好ISAPIRuntime實例後初始化工做就完成了第一個階段,整個過程以下圖所示:

理論的解說通常都是枯燥的,研究一個代碼框架更是如此,彷佛除了對大量的源碼加以解釋以外無話可說,可是這又是不可缺乏的,不然應用這樣的框架起來總有不放心之感,總有很多的坑要踩。更進一步講,一個好的框架應該給它的使用者足夠的擴展空間(尤爲是像MVC這樣的基礎框架),對框架自己沒有很好的把握則對於框架的擴展彷佛就只能尋找別人的「成功」經驗了,然而生搬硬套歷來不是解決問題的好方法,合理運用他人經驗與創造性的解決方案都離不開對框架的深刻理解,從這方面來講代碼分析其實強於抽象的說明,由於代碼的邏輯是肯定的,代碼的語言說服力其實強於書面語言(固然是指編寫良好的代碼)。固然對於代碼以外的討論也是很是必要甚至更加劇要的,好比探討框架設計的思路和模式,框架應用的相關實踐乃至對框架的擴展等等。此一系列文章都是基於Asp.net Mvc框架的源碼(包括Asp.net的一部分)對框架的基本設計與實現做出分析,另外參考了本身的一些項目以及當前一些優秀的開源項目(好比orchard)來討論框架的應用與擴展。

相關文章
相關標籤/搜索