zoukankan      html  css  js  c++  java
  • Orchard源码分析(5.1):Host初始化(DefaultOrchardHost.Initialize方法)

    概述
    Orchard作为一个可扩展的CMS系统,是由一系列的模块(Modules)或主题(Themes)组成,这些模块或主题统称为扩展(Extensions)在初始化或运行时需要对扩展进行安装:DefaultOrchardHost.SetupExtensions方法。
    当添加新的扩展、删除扩展或修改扩展源码后,需要通知扩展加载器(Extension Loader)重新加载或完成一些清理工作,所以需要进行监视:DefaultOrchardHost.MonitorExtensions方法。
    Orchard 是一个多租户(Tenant)系统,也就是我们通常所是说的子站点,它允许一个Orchard应用程序中包含多个不同域名的子站点。每个子站点对应一个 Shell,从源码角度上看,Host对应的是IOrchardShell接口及其实现DefaultOrchardShell类。在Orchard启动 或运行时,需要创建并激活:DefaultOrchardHost.CreateAndActivateShells方法。
     
    在调用DefaultOrchardHost.Initialize方法进行初始化时,会通过调用BuilderCurrent方法间接顺序调用上述三个方法。请看BuildCurrent方法的源码:
             IEnumerable<ShellContext > BuildCurrent() {
                if (_shellContexts == null ) {
                    lock (_syncLock) {
                        if (_shellContexts == null ) {
                            SetupExtensions();
                            MonitorExtensions();
                            CreateAndActivateShells();
                        }
                    }
                }
     
                return _shellContexts;
            }
     
    这 里有个对_shellContexts是否为null的判断,以避免重复安装扩展。CreateAndActivateShells方法成功激活 Shell后,_shellContexts将不会为null。关于ShellContext,在会在后面Shell相关的文章中有所分析。
    由于BuildCurrent方法并不会只供Initialize方法调用,还可能被BeginRequest事件处理方法调用,所以lock住以保证线程安全。
      
    一、安装扩展:SetupExtensions方法
    DefaultOrchardHost.SetupExtensions 方法实际上是调用的ExtensionLoaderCoordinator.SetupExtensions方法,在下文中提到 SetupExtensions指的就是后者。通过字面上看ExtensionLoaderCoordinator可以叫做"扩展加载器的协调器"。
     
    安装扩展包括这些步骤:
    1、创建扩展加载上下文(ExtensionLoadingContext)
    SetupExtensions方法会调用私有的CreateLoadingContext方法获取可用的扩展:
                var availableExtensions = _extensionManager
                    .AvailableExtensions()
                    .Where(d => DefaultExtensionTypes.IsModule(d.ExtensionType) || DefaultExtensionTypes .IsTheme(d.ExtensionType))
                    .OrderBy(d => d.Id)
                    .ToList();
      
    _extensionManager是扩展管理器ExtensionManager,由它的AvailableExtensions方法来调度扩展的搜索和收集(Harvest):
             //以下代码来自ExtensionManager类
             public IEnumerable <ExtensionDescriptor> AvailableExtensions() {
                return _cacheManager.Get("AvailableExtensions" , ctx =>
                    _parallelCacheContext
                        .RunInParallel(_folders, folder => folder.AvailableExtensions().ToList())
                        .SelectMany(descriptors => descriptors)
                        .ToReadOnlyCollection());
            }
     
    ExensionManager采用并行(Parallel)的方式以提高效率,但可以通过在配置文件HostComponents.config中设置Orchard.Caching.DefaultParallelCacheContext类型的Disabled属性为false以禁用并行机制。
     
    _folders是一个集合,它包含ModuleFolders、CoreModuleFolders和ThemeFolders型的三个对象。通过上面的代码看起来是这三个类在负责搜索和收集工作。实际上这三个类会调用扩展收集器ExtensionHarvester的HarvestExtensions方法来做实际的工作。该方法根据不同的参数在~/Modules、~/Core和~/Themes三个目录的所有一级子目录中搜索Module.txt和Theme.txt文件。每一个Module.txt或Theme.txt文件都会被反序列化成一个扩展描述ExtensionDescriptor对象。扩展描述对象包括扩展名称、所在路径、分类、作者和扩展ID等信息,其中扩展ID在下面的分析中经常被用到,它指扩展目录的名称,比如~/Modules/Orchard.Blogs的扩展ID是"Orchard.Blogs"。
     
    不难看出SetupExtensions方法中的availableExtensions是一个按扩展ID排序后的List<ExtensionDescriptor>型的集合,这里称为扩展描述集合。依赖于这个集合,来创建一个扩展加载上下文ExtensionLoadingContext对象。
     
    扩展加载上下文类主要定义了一些属性,这些的属性虽不多,但意义复杂:
    (1)、PreviousDependencies:List<DependencyDescriptor>型。扩展依赖描述DependencyDescriptor 对象的集合,是通过DefaultDependenciesFolder类对~/App_Data/Dependencies /dependencies.xml文件反序列化而来。如果是第一次加载扩展,该集合当然就会为null。
                var previousDependencies = _dependenciesFolder.LoadDescriptors().ToList();
     
    扩展依赖描述是包含了扩展的名称、扩展加载器名称、扩展的虚拟路径和"扩展所引用的其他扩展"的描述DependencyReferenceDescriptor对象集合:
         public class DependencyDescriptor {
            public DependencyDescriptor() {
                References = Enumerable.Empty<DependencyReferenceDescriptor >();
            }
            public string Name { getset; }
            public string LoaderName { getset; }
            public string VirtualPath { getset; }
            public IEnumerable <DependencyReferenceDescriptor> References { getset ; }
        }
     
        public class DependencyReferenceDescriptor {
            public string Name { getset; }
            public string LoaderName { getset; }
            public string VirtualPath { getset; }
        }
     
    其中Name为扩展的名称,和上面提到的扩展ID是相同的;LoaderName为扩展加载器名称,这后面会详细介绍;VirtualPath为扩展的虚拟路径,可能是目录路径或文件路径——这要看是被哪个扩展加载器加载。
      
    PreviousDependencies属性实际上是冗余的。而previousDependencies下面会用到。
     
    (2)、DeletedDependencies: List<DependencyDescriptor>型。最后一次在系统中成功被加载的、但当前已经被移除的扩展的扩展依赖描述
    是上面搜索得到的扩展描述集合availableExtensions与previousDependencies比较筛选而来,用于在后面的操作中可以删除扩展相关的程序集。如果没有对扩展进行过删除操作,该集合当然就会为空。
     
    (3)、AvailableExtensionsProbes:IDictionary<string, IEnumerable<ExtensionProbeEntry>>型。按扩展ID分组的的扩展探测条目ExtensionProbeEntry对象集合。扩展ID前面提到过,实际上就是扩展的目录名称。
    扩展探测条目由扩展加载器探测(Probe)而来。具体某一个扩展ID对应的扩展探测条目集合(IEnumerable<ExtensionProbeEntry>)是按探测条目优先级(Priority)、"扩展依赖的虚拟路径的最后修改时间"倒序、扩展加载器Order属性三个条件排序的集合。排序算法请看ExtensionLoaderCoordinator类的SortExtensionProbeEntries方法。
     
    生成该属性的值有三个步骤,探测(Probe)、分组(Group)和排序(Sort)。
    Orchard提供了5个扩展加载器:CoreExtensionLoader,ReferencedExtensionLoader,PrecompiledExtensionLoader,DynamicExtensionLoader,RawThemeExtensionLoader。这些扩展器探对根据扩展描述探测出的"扩展探测条目"的数量,以及"扩展探测条目"优先级(Priority)也不尽相同:
    CoreExtensionLoader只会探测~/Core目录下的扩展;
    ReferencedExtensionLoader会探测引用了外部程序集的扩展;
    PrecompiledExtensionLoader会探测扩展目录下的bin子目录有"<扩展ID>.dll"的扩展;
    DynamicExtensionLoader会探测在扩展目录下有C#项目文件"<扩展ID>.csproj"的扩展;
    RawThemeExtensionLoader只会探测~/Themes目录下的扩展(即主题)。该加载器还比较特殊,如果在主题目录下有C#项目文件"<主题ID>.csproj"或者主题目录下的bin子目录有"<主题名称>.dll",就不会继续使用该扩展探测器进行探测。
    注 意:一个扩展虽然会被5个扩展加载器探测,但并不一定会获取5个扩展探测条目,并且扩展最终只会被一个扩展加载器进行加载。所以扩展探测条目集合的顺序至 关重要,它是决定用哪一个扩展加载器来加载对应的扩展的重要因素(另外一个因素是当扩展引用了其他的扩展,被引用的扩展使用的是 DynamicExtensionLoader加载,则前者不能采用PrecompiledExtensionLoader来加载,您可以想想这是为什 么)。
     
    扩展描述ExtensionDescriptor对应的若干条扩展探测条目被探测出,再根据扩展ID进行分组:
                var availableExtensionsProbes1 = _parallelCacheContext
                    .RunInParallel(availableExtensions, extension =>
                        _loaders.Select(loader => loader.Probe(extension)).Where(entry => entry != null).ToArray())
                    .SelectMany(entries => entries)
                    .GroupBy(entry => entry.Descriptor.Id);
      
    然后根据探测条目优先级(Priority)、"扩展依赖的虚拟路径的最后修改时间"及扩展加载器的Order属性排序:
                var availableExtensionsProbes = _parallelCacheContext
                    .RunInParallel(availableExtensionsProbes1, g =>
                        new { Id = g.Key, Entries = SortExtensionProbeEntries(g, virtualPathModficationDates)})
                    .ToDictionary(g => g.Id, g => g.Entries, StringComparer.OrdinalIgnoreCase);
      
    排序算法在SortExtensionProbeEntries方法进行。
    探测条目优先级是指ExtensionProbeEntry的Priority属性。五个扩展加载器探测出的条目优先级:
    CoreExtensionLoader  扩展探测条目优先级为100;
    ReferencedExtensionLoader 扩展探测条目优先级为100;
    PrecompiledExtensionLoader 扩展探测条目优先级为0;
    DynamicExtensionLoader会 扩展探测条目优先级为0;
    RawThemeExtensionLoader 扩展探测条目优先级为0。
     
    "扩展依赖的虚拟路径"是指ExtensionProbeEntry的VirtualPathDependencies属性,是一个字符串集合。请注意它并不是指扩展的虚拟路径。
    不同的扩展加载器对"扩展依赖的虚拟路径"的理解是不一样的:
    CoreExtensionLoader:无扩展依赖虚拟路径
    ReferencedExtensionLoader:~/bin/<扩展ID>.dll文件
    PrecompiledExtensionLoader:~/<Core、Modules或Themes>/<扩展ID>/bin/<扩展ID>.dll文件
    DynamicExtensionLoader:首先将~/<Core、Modules或Themes>/<扩展ID>/<扩展ID>.csproj反序列化(该文件就是一XML文件)再从中提取。扩展依赖路径就包含四部分:一是".csproj"文件本身;二是扩展项目包含的".cs"等源文件;三是扩展项目引用的第三方程序集;四是扩展项目引用的其他扩展(仅~/Modules和~/Theme目录下的扩展)的路径,这会引起递归搜索。
    RawThemeExtensionLoader:无扩展依赖虚拟路径
     
    不同的扩展加载器的Order属性值也是不一样的:
    CoreExtensionLoader:10
    ReferencedExtensionLoader:20
    PrecompiledExtensionLoader:30
    DynamicExtensionLoader:100
    RawThemeExtensionLoader:10
     
    (4)、ReferencesByName:IDictionary<string, IEnumerable<ExtensionReferenceProbeEntry>>型。按扩展引用探测条目所属的扩展ID(ExtensionDescriptor的Id属性)分组的扩展引用探测条目ExtensionReferenceProbeEntry集合。
    与"扩展探测条目"类似,"扩展引用探测条目"由也是由扩展加载器探测而来,只有PrecompiledExtensionLoader和DynamicExtensionLoader这两种探测器有实际的功能。
    PrecompiledExtensionLoader将探测出~/<Core、Modules或Themes>/<扩展ID>/bin/<扩展ID>.dll,即扩展项目引用的其他程序集。该扩展加载器探测出来的"扩展引用探测条目(ExtensionReferenceProbeEntry)"的Name属性值为"<扩展ID>.dll"文件的不包含扩展名的文件名。
    DynamicExtensionLoader 将探测出~/<Core、Modules或Themes>/<扩展ID>/<扩展ID>.csproj文件中描述 的、扩展项目引用的其他程序集或其他项目。该扩展加载器探测出来的"扩展引用探测条目(ExtensionReferenceProbeEntry)"的 Name属性值,如果是程序集则程序集的短名称,如果是源程序项目则为项目"<项目名称>.csproj"文件的不包含扩展名的文件名。
     
                var references = _parallelCacheContext
                    .RunInParallel(availableExtensions, extension => _loaders.SelectMany(loader => loader.ProbeReferences(extension)).ToList())
                    .SelectMany(entries => entries)
                    .ToList();
                 //......
                 var referencesByName = references
                    .GroupBy(reference => reference.Descriptor.IdStringComparer.OrdinalIgnoreCase)
                    .ToDictionary(g => g.Key, g => g.AsEnumerable(), StringComparer.OrdinalIgnoreCase);
      
    (5)、ReferencesByModule:IDictionary<string, IEnumerable<ExtensionReferenceProbeEntry>>型。按扩展引用探测条目名称(ExtensionReferenceProbeEntry的Name属性)分组的扩展引用探测条目集合。ReferencesByModule与ReferenceByName类似,唯一的不同就是分组方式。
     
                  var referencesByModule = references
                    .GroupBy(entry => entry.NameStringComparer .OrdinalIgnoreCase)
                    .ToDictionary(g => g.Key, g => g.AsEnumerable(), StringComparer .OrdinalIgnoreCase);
      
    (6)、VirtualPathModficationDates:ConcurrentDictionary<string, DateTime>型。扩展对应的"扩展依赖虚拟路径最后修改时间"字典。该属性是冗余的。
    (7)、AvailableExtensions:List<ExtensionDescriptor>型。当前可用的扩展描述(ExtensionDescriptor型)对象集合。该集合是上面获取的availableExtensions集合通过扩展ID(也就是扩展的目录名称)和扩展之间的依赖关系两个条件排序而来,这类似于Vistual Studio解决方案的按"项目生成顺序"显示的列表。
                 var sortedAvailableExtensions =
                    availableExtensions.OrderByDependenciesAndPriorities(
                        (item, dep) => referencesByModule.ContainsKey(item.Id) &&
                                       referencesByModule[item.Id].Any(r => StringComparer.OrdinalIgnoreCase.Equals(dep.Id, r.Name)),
                        item => 0)
                        .ToList();
      
    2、从扩展加载上下文(Extension Loading Context)获取已经被移除的扩展,并通知扩展对应的扩展加载器(Extension Loader)
                foreach (var dependency in context.DeletedDependencies) {
                    Logger.Information( "Extension {0} has been removed from site" , dependency.Name);
                    foreach (var loader in _loaders) {
                        if (dependency.LoaderName == loader.Name) {
                            loader.ExtensionRemoved(context, dependency);
                        }
                    }
                }
      
    如 上所述,扩展加载上下文的DeletedDependencies属性保存了已经被删除的扩展的依赖描述信息。扩展之前被哪个扩展加载器所成功加载,就交 由它来定义相应的删除动作(Delete Action)。删除动作实际上是一系列的方法,他们将会被保存在扩展加载上下文的DeleteActions属性中,该属性是一个Action委托集合。也就是说,在这里并不会进行真正的清理工作。下面列出五个扩展加载器定义的删除动作:
    CoreExtensionLoader:~/Core下的模块总是需要被加载,所以没有定义删除动作。
    ReferencedExtensionLoader:删除~/bin/<扩展ID>.dll文件
    PrecompiledExtensionLoader:删除~/App_Data/Dependencies/<扩展ID>.dll文件
    DynamicExtensionLoader:无操作
    RawThemeExtensionLoader:无操作
     
    程序集可能位于~/Bin或~/App_Data/Dependencies目录。删除~/Bin目录的程序集会设置"重启应用程序域标记"为true;删除~/App_Data/Dependencies目录的程序集会判断程序集是否已经被应用程序域加载,如果已经加载则设置"重启应用程序域标记"为true。
     
    注 意,对于PrecompiledExtensionLoader和DynamicExtensionLoader这两个扩展加载器在激活扩展的时候,如果 扩展引用了第三方程序集,也会被复制到~/App_Data/Dependencies目录中。但是在删除扩展的时候,并不会删除这些程序集。因为 Orchard还无法判断除了相应扩展之外,是否还有另外的扩展也引用了这些程序集。这意味着有可能需要手动到~/App_Data /Dependencies目录去删除确定不会用到的程序集。
     
    3、扩展加载器激活扩展(Activate Extensions)
                foreach (var extension in context.AvailableExtensions) {
                    ProcessExtension(context, extension);
                }
     
    扩展加载器可能会把扩展需要用到的程序集的复制操作(Copy Action)放入扩展加载器上下文中的CopyActions属性中,该属性是一个Action委托集合。就是说,在这里并不会进行真正的复制工作。下面列出五个扩展加载器定义的复制动作:
    CoreExtensionLoader:~/Core下的模块对应的Orchard.Core.dll已经被放在了~/Bin目录下,所以没有定义复制动作。
    ReferencedExtensionLoader:程序集右键被放在了~/Bin目录下,也没有定义复制操作。
    PrecompiledExtensionLoader:复制~/<Core、Modules或Themes>/<扩展ID>/bin/<扩展ID>.dll文件到~/App_Data/Dependencies目录。如果扩展引用了第三方程序集,也会进行复制。
    DynamicExtensionLoader:如果扩展引用了第三方程序集,则将这些程序集复制到~/App_Data/Dependencies目录。
    RawThemeExtensionLoader:无操作
     
    注意:
    (1)、扩展有可能引用了其他扩展,但是被引用的扩展总是会先被激活。
    (2)、DynamicExtensionLoader扩展加载器并不会在这里对相关扩展进行动态编译。
     
    4、执行程序集复制或删除操作
               ProcessContextCommands(context);
      
    根据扩展加载上下文的DeleteActions属性和CopyActions属性,完成程序集的删除或复制操作:
            private void ProcessContextCommands(ExtensionLoadingContext ctx) {
                Logger.Information( "Executing list of operations needed for loading extensions..." );
                foreach (var action in ctx.DeleteActions) {
                    action();
                }
     
                foreach (var action in ctx.CopyActions) {
                    action();
                }
            }
      
    5、将扩展依赖信息存储到xml文件中
                _dependenciesFolder.StoreDescriptors(context.NewDependencies);
                  _extensionDependenciesManager.StoreDependencies(context.NewDependencies,  desc => GetExtensionHash(context, desc));
      
    将所有扩展的依赖关系写入到~/App_Data/Dependencies/dependencies.xml文件中。
    另,还会写入~/App_Data/Dependencies/dependencies_compiled.xml文件中,这里暂不关注。
     
    6、如有必要,重启应用程序域
                if (context.RestartAppDomain) {
                    Logger.Information( "AppDomain restart required." );
                    _hostEnvironment.RestartAppDomain();
                }
      
    如果"重启应用程序域标记"RestartAppDomain为true,则会重启应用程序域。
     
    7、总结说明
    提 取几个重要细节进行总结说明:搜索扩展(Look for Extensions)、探测扩展(Probe  Extensions)、获取已经被移除的扩展的依赖、检测扩展引用(Probe Extension  References)、激活扩展(Activate Extensions)。
    (1)、搜索扩展
    关于扩展搜索上文已有描述,在~/Modules、~/Core和~/Themes三个目录的所有一级子目录中搜索Module.txt和Theme.txt文件。
    每一个Module.txt或Theme.txt文件都会被反序列化成扩展描述ExtensionDescriptor对象,组合成一个按扩展目录名称排序后的List<ExtensionDescriptor>对象以供后面使用。
    然后根据目录名称判断是否有重复的扩展,如果有相同名称的扩展则会报异常。比如在~/Modules目录有个Lucene扩展,在~/Core或~/Themes就不能有相同目录名称的扩展。
    有必要说一下,因为扩展加载器(Extension Loader)的原因,请务必保证扩展的程序集名称扩展目录名称一致。当新建一个扩展项目的时候默认就是这样,也就是说不要去修改它。
    (2)、探测扩展
    不同的扩展加载器有不同的探测策略,关于这方面上文已有比较详细的描述。
    (3)、获取已经被移除的扩展的依赖
    我们知道,不管是Module还是Theme的扩展,都是独立的项目,项目除了有自己程序集,还可能依赖第三方程序集或其他扩展项目。
    ~/App_Data/Dependencies/dependencies.xml扩展依赖文件保存了最后一次成功加载扩展时,扩展、扩展加载器和扩展所引用的程序集列表。
    读取扩展依赖文件将之反序列化最终为一个List<DependencyDescriptor>对象(依赖描述)。
    在SetupExtensions方法中,会比较依赖描述和本次查找而来的扩展,如果检测到某些扩展已经被移除,则相关的程序集dll文件也应该被移除。dll移除工作由对应的扩展加载器配合完成。
    (4)、探测扩展引用
    实 际上只有PrecompiledExtensionLoader和DynamicExtensionLoader这两种探测器有实际的功能。 PrecompiledExtensionLoader将提取在“~/<Core、Modules或Themes>/<扩展 ID>/bin”目录下“<扩展ID>.dll”的程序集;DynamicExtensionLoader将提取在 “~/<Modules或Themes>/<扩展ID>.csproj”项目文件描述的引用的第三方程序集或其他扩展项目的程序 集(PrecompiledExtensionLoader不会对~/Core扩展目录的核心扩展进行探测)。
    (5)、激活扩展
    Orchard提供了5个扩展加载器,针对不同的加载、激活策略:
    CoreExtensionLoader
    如 果“Module.txt”文件来自于"~/Core"文件夹,CoreModuleLoader将返回来自于Orchard.Core.dll 中,"Orchard.Core.<扩展ID>"命名空间下的所有类型。Orchard.Core.dll是一个特殊的程序集,它包含了 Orchard核心模块,在Orchard框架基础上提供一些基本功能。
    ReferencedExtensionLoader
    在 “~/bin”目录中查找“Module.txt”文件中模块名对应的程序集,如果这个程序集存在,它将加载并返回改程序集的所有类型。这种加载机用于当 所有模块都是预先编译好的,并且其dll都存储在“~/bin”目录中的情况,这是一种典型“ASP.NET MVC”应用程序方式。
    PrecompiledExtensionLoader
    如果“Module.txt”文件来自于"~/Core"、"~ /Modules"、"~/Themes" 文件夹,PrecompiledExtensionLoader将在“~/<Core、Modules 或Themes>/<扩展ID>/bin”中查找名为<扩展ID>.dll的程序集。如果这个文件存在,它将被复制到"~ /App_Data/Dependencies"文件夹下,这是一个特殊的文件夹,在~/Web.config文件中配置进行过配置,是用于 ASP.NET查找“~/bin”文件夹以外程序集的地方。
    DynamicExtensionLoader
    如 果“Module.txt”文件来自于"~/Core"、"~/Modules"、"~/Themes"  文件夹,DynamicExtensionLoader将在“~/<Core、Modules或Themes>/<扩展ID>” 目录中查找.csproj文件。如果这个文件存在,这个加载器将使用Orchard编译管理器根据.csproj文件来编译程序集并返回改程序集的所有类 型——Orchard中扩展的动态编译指的就是这部分了。
    RawThemeExtensionLoader
    如 果“Module.txt”文件来自于"~/Themes"  文件夹,则由RawThemeExtensionLoader负责加载。其实基本上不做什么事情,因为如果一个模块有程序集或.csproj文件,就轮不 到它,而是交给PrecompiledExtensionLoader或DynamicExtensionLoader来处理了。
     
    二、监视扩展:MonitorExtensions方法
    如《IIS 5.0 和 6.0 的 ASP.NET 应用程序生命周期概述》所述,某些操作将导致应用程序重新启动。除此之外,包括扩展改变在内的一些其他操作也将导致Orchard重启。为了做到这一点,Orchard通过调用MonitorExtensions方法监视扩展的变化。
     
    首先会监视~/Modules和~/Themes目录的最后修改时间(扩展的增删操作)的变化。通过扩展加载器还会对扩展进行监视:
    CoreExtensionLoader:不监视,Orchard.Core.dll在~/Bin目录中,有变动自然会重启。
    ReferencedExtensionLoader:不监视,因为程序集也是放在~/Bin目录
    PrecompiledExtensionLoader:监视~/<Core、Modules或Themes>/<扩展ID>/bin/<扩展ID>.dll文件(如果存在的话),以及~/<Core、Modules或Themes>/<扩展ID>/bin目录。
    DynamicExtensionLoader:监视~/<Core、Modules或Themes>/<扩展ID>/<扩展ID>.csproj文件和所有.cs文件,以及.csproj文件中描述的项目引用(会引起递归搜索)
    RawThemeExtensionLoader:不监视,改改UI就重启那受不了。
    需要注意一点,尽管一个扩展是由一个扩展加载器加载,却受多个扩展加载器监视。
     
    最后会监视~/App_Data/hrestart.txt最后修改时间的变化。
     
    MonitorExtensions方法会在Orchard初始化和每次处理BeginRequest事件的时候得以执行。
    初始化时执行该方法的目的在于处理一种边界情况,那就是在扩展被探测完的时候正进行安装扩展的时候,如果扩展有扩展增删改的操作,能够及时进行某些处理。
    运行时处理BeginRequest事件的时候,也会调用该方法监视到扩展的变化。
    另,在分析Orchard.Caching.CacheModule的时候,也提到过监视缓存到期的机制。适当的时候我们专门就"监视"功能进行分析。
     
    三、创建和激活Shell:CreateAndActivateShells方法
    首 先由ShellSettingsManager从~/App_Data/Sites目录的子目录中搜索Settings.txt文件,并将其反序列化为 ShellSettings对象。一系列ShellSettings对象形成一个集合。如果ShellSettings对象集合不为空,则使用 ShellContextFactory.CreateShellContext为每个ShellSettings对象创建对应的 ShellContext对象,否则使用ShellContextFactory.CreateSetupContext创建一个安装上下文 ShellContext对象。
    针对具体的ShellContext,调用其包含的Shell(DefaultOrchardShell)的Activate方法进行激活。
    另外,会对ShellContext对象集合进行缓存,当需要重新安装扩展时,只需要将其设置null,在处理下一次BeginRequest事件时就能够重新启动安装扩展的操作。BuildCurrent方法进行该判断。
     
    关于Shell,我们有专门的篇幅来介绍,包括Shell是什么及其作用、更详细创建及激活操作分析。
     
    相关类型:
    Orchard.Environment.DefaultOrchardHost : IOrchardHost
    Orchard.Environment.Extensions.ExtensionLoadingContext
    Orchard.Environment.Extensions.ExtensionLoaderCoordinator : IExtensionLoaderCoordinator
    Orchard.Environment.Extensions.ExtensionManager : IExtensionManager
    Orchard.Environment.Extensions.Folders.ExtensionHarvester : IExtensionHarvester
    Orchard.Environment.Extensions.Folders.ModuleFolders: IExtensionFolders
    Orchard.Environment.Extensions.Folders.CoreModuleFolders: IExtensionFolders
    Orchard.Environment.Extensions.Folders.ThemeModuleFolders: IExtensionFolders
    Orchard.FileSystems.Dependencies.DefaultDependenciesFolder:IDependenciesFolder
    Orchard.Environment.Extensions.Models.ExtensionDescriptor
    Orchard.Environment.Extensions.Loaders.ExtensionProbeEntry
    Orchard.Environment.Extensions.Loaders.ExtensionReferenceProbeEntry
    Orchard.FileSystems.Dependencies.DependencyDescriptor
    Orchard.FileSystems.Dependencies.DependencyReferenceDescriptor
    Orchard.Environment.Extensions.ExtensionEntry
     
    Orchard.Environment.Extensions.ExtensionMonitoringCoordinator : IExtensionMonitoringCoordinator
    Orchard.Environment.Configuration.ShellSettings
    Orchard.Environment.Configuration.ShellSettingsManager: IShellSettingsManager
     
    Orchard.Environment.ShellBuilders.ShellContext
    Orchard.Environment.ShellBuilders.ShellContextFactory: IShellContentFactory
    Orchard.Environment.ShellBuilders.ShellContainerFactory
     
    Orchard.Environment.ShellBuilders.CompositionStrategy: ICompositionStrategy
     
    Orchard.Caching.DefaultParallelCacheContext
     
  • 相关阅读:
    Entity Framework Core 2.0 新特性
    asp.net core部署时自定义监听端口,提高部署的灵活性
    asp.net core使用jexus部署在linux无法正确 获取远程ip的解决办法
    使用xshell连接服务器,数字键盘无法使用解决办法
    使用Jexus 5.8.2在Centos下部署运行Asp.net core
    【DevOps】DevOps成功的八大炫酷工具
    【Network】Calico, Flannel, Weave and Docker Overlay Network 各种网络模型之间的区别
    【Network】UDP 大包怎么发? MTU怎么设置?
    【Network】高性能 UDP 应该怎么做?
    【Network】golang 容器项目 flannel/UDP相关资料
  • 原文地址:https://www.cnblogs.com/lhxsoft/p/5322580.html
Copyright © 2011-2022 走看看