理論的解說一般都是枯燥的,研究一個代碼框架更是如此,似乎除了對大量的源碼加以解釋之外無話可說,但是這又是不可缺少的,否則應(yīng)用這樣的框架起來總有不放心之感,總有不少的坑要踩。更進(jìn)一步講,一個好的框架應(yīng)該給它的使用者足夠的擴(kuò)展空間(尤其是像MVC這樣的基礎(chǔ)框架),對框架本身沒有很好的把握則對于框架的擴(kuò)展似乎就只能尋找別人的“成功”經(jīng)驗(yàn)了,然而生搬硬套從來不是解決問題的好方法,合理運(yùn)用他人經(jīng)驗(yàn)與創(chuàng)造性的解決方案都離不開對框架的深入理解,從這方面來說代碼分析其實(shí)強(qiáng)于抽象的說明,因?yàn)榇a的邏輯是確定的,代碼的語言說服力其實(shí)強(qiáng)于書面語言(當(dāng)然是指編寫良好的代碼)。當(dāng)然對于代碼之外的討論也是非常必要甚至更加重要的,比如探討框架設(shè)計的思路和模式,框架應(yīng)用的相關(guān)實(shí)踐乃至對框架的擴(kuò)展等等。此一系列文章都是基于Asp.net Mvc框架的源碼(包括Asp.net的一部分)對框架的基本設(shè)計與實(shí)現(xiàn)作出分析,另外參考了自己的一些項(xiàng)目以及當(dāng)前一些優(yōu)秀的開源項(xiàng)目(比如orchard)來討論框架的應(yīng)用與擴(kuò)展。

Asp.net Mvc是當(dāng)前使用比較多的web框架,也是比較先進(jìn)的框架,目前.net的大部分源碼都已經(jīng)開放,這大大方便了我們對Asp.net Mvc的分析,下面就從Http請求進(jìn)入Mvc框架處理之前的基本流程說起。

由于各IIS版本和工作模式(經(jīng)典模式、集成模式)的不同,Http請求進(jìn)入Asp.net的處理通道并不一樣,這里不去細(xì)究里面的細(xì)節(jié),就從創(chuàng)建應(yīng)用程序域開始:

AppManagerAppDomainFactory分析

注:AppDomainFactory及AppManagerAppDomainFactory類在System.Web.Hosting中實(shí)現(xiàn)

在創(chuàng)建Appdomain時會調(diào)用IAppDomainFactory接口,該接口的實(shí)現(xiàn)如下:

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

 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);         } }

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

該實(shí)現(xiàn)會調(diào)用AppManagerAppDomainFactory完成實(shí)際的創(chuàng)建過程。

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

  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;             }         }   }

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

代碼的主要作用,就是通過ApplicationManager的CreateObjectInternal創(chuàng)建AppDomain,創(chuàng)建HostingEnvironment等,最終獲取ISAPIRuntime的實(shí)例,然后讓非托管代碼調(diào)用。

ApplicationManager分析

注:ApplicationManager類在System.Web.Hosting中實(shí)現(xiàn)

首先看ApplicationManager類中的靜態(tài)的創(chuàng)建ApplicationManager對象的方法:

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

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; }

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

如果HostingEnvironment已經(jīng)創(chuàng)建則可以直接返回當(dāng)前HostingEnvironment設(shè)置的ApplicationManager,如果沒有則創(chuàng)建新的ApplicationManager實(shí)例。

然后看ApplicationManager的CreateObjectInternal方法:

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

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;     }

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

首先要先取得HostingEnvironment的實(shí)例,然后通過該實(shí)例的CreateWellKnownObjectInstance方法返回上述Create方法需要的ISAPIRuntime的實(shí)例。先來看如何獲取HostingEnvironment實(shí)例的方法GetAppDomainWithHostingEnvironment。

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

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;         }     }

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

首先會檢查字典是否會有已經(jīng)存在的HostingEnvironment實(shí)例,如果有就返回,沒有就會創(chuàng)建一個新的并保存到字典中,查看相關(guān)代碼發(fā)現(xiàn)最終會調(diào)用ApplicationManager的私有方法CreateAppDomainWithHostingEnvironment創(chuàng)建AppDomain和HostingEnvironment。

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

  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; }

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

可以看到代碼創(chuàng)建了AppDomain和HostingEnvironment實(shí)例,創(chuàng)建HostingEnvironment實(shí)例以后,緊接著會調(diào)用其Initialize方法來進(jìn)行初始化,然后返回對象實(shí)例。

HostingEnvironment分析

Initialize初始化方法,注意該方法的第一個參數(shù)是this,也就是ApplicationManager實(shí)例自身,這樣會在HostingEnvironment中設(shè)置ApplicationManager,因而初始化之后可以通過HostingEnvironment獲取ApplicationManager 。Initialize方法調(diào)用HttpRuntime的靜態(tài)方法,進(jìn)行一些初始化工作(其中會調(diào)用BuildManager的InitializeBuildManager方法進(jìn)行初始化另外一些工作,其中包括編譯App_Code目錄下所有的.NET源代碼)。最后如果HostingEnvironment初始化失敗時會設(shè)置hostingInitFailed為true。

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

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;     } }

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

創(chuàng)建HostingEnvironment后,會調(diào)用其方法CreateWellKnownObjectInstance創(chuàng)建ISAPIRuntime。創(chuàng)建好ISAPIRuntime實(shí)例后初始化工作就完成了第一個階段,整個過程如下圖所示:

平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),游戲開發(fā),動畫培訓(xùn)

理論的解說一般都是枯燥的,研究一個代碼框架更是如此,似乎除了對大量的源碼加以解釋之外無話可說,但是這又是不可缺少的,否則應(yīng)用這樣的框架起來總有不放心之感,總有不少的坑要踩。更進(jìn)一步講,一個好的框架應(yīng)該給它的使用者足夠的擴(kuò)展空間(尤其是像MVC這樣的基礎(chǔ)框架),對框架本身沒有很好的把握則對于框架的擴(kuò)展似乎就只能尋找別人的“成功”經(jīng)驗(yàn)了,然而生搬硬套從來不是解決問題的好方法,合理運(yùn)用他人經(jīng)驗(yàn)與創(chuàng)造性的解決方案都離不開對框架的深入理解,從這方面來說代碼分析其實(shí)強(qiáng)于抽象的說明,因?yàn)榇a的邏輯是確定的,代碼的語言說服力其實(shí)強(qiáng)于書面語言(當(dāng)然是指編寫良好的代碼)。當(dāng)然對于代碼之外的討論也是非常必要甚至更加重要的,比如探討框架設(shè)計的思路和模式,框架應(yīng)用的相關(guān)實(shí)踐乃至對框架的擴(kuò)展等等。此一系列文章都是基于Asp.net Mvc框架的源碼(包括Asp.net的一部分)對框架的基本設(shè)計與實(shí)現(xiàn)作出分析,另外參考了自己的一些項(xiàng)目以及當(dāng)前一些優(yōu)秀的開源項(xiàng)目(比如orchard)來討論框架的應(yīng)用與擴(kuò)展。


http://www.cnblogs.com/ssxg/p/7077187.html