標籤:mvc 失敗 工作模式 自身 http請求 conf public ppi ret
Asp.net Mvc是當前使用比較多的web架構,也是比較先進的架構。我打算根據自己的實際項目經驗以及相關的源碼和一些使用Asp.net Mvc的優秀項目(主要是orchard)來說一說自己對於Asp.net Mvc原理的理解和一些實踐經驗。目前.net的大部分源碼都已經開放,這大大方便了我們對Asp.net Mvc的分析,下面就從Http請求進入Mvc架構處理之前的基本流程說起。
由於各IIS版本和工作模式(傳統模式、整合模式)的不同,Http請求進入Asp.net的處理通道並不一樣,這裡不去細究裡面的細節,就從建立應用程式定義域開始:
AppManagerAppDomainFactory分析
註:AppDomainFactory及AppManagerAppDomainFactory類在System.Web.Hosting中實現
在建立Appdomain時會調用IAppDomainFactory介面,該介面的實現如下:
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完成實際的建立過程。
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的執行個體,然後讓Unmanaged 程式碼調用。
ApplicationManager分析
註:ApplicationManager類在System.Web.Hosting中實現
首先看ApplicationManager類中的靜態建立ApplicationManager對象的方法:
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初始化流程分析1