从上一篇可以看出Orchard在处理拓展模块时主要有两个组件,一个是Folder另一个是Loader,前者用于搜索后者用于加载。
其中Folder一共有三个:Module Folder、Core Folder、ThemeFolder。Loader有引用加载器(Referenced Module Loader)、核心模块加载器(Core Module Loader)、预编译模块加载器(Precompiled Module Loader)、动态模块加载器(Dynamic Module Loader)。它们在代码里可以看到,在创建容器时对与Folder和Loader的注册:
1 builder.RegisterType<ExtensionLoaderCoordinator>().As<IExtensionLoaderCoordinator>().SingleInstance(); 2 builder.RegisterType<ExtensionMonitoringCoordinator>().As<IExtensionMonitoringCoordinator>().SingleInstance(); 3 builder.RegisterType<ExtensionManager>().As<IExtensionManager>().SingleInstance(); 4 { 5 builder.RegisterType<ExtensionHarvester>().As<IExtensionHarvester>().SingleInstance(); 6 builder.RegisterType<ModuleFolders>().As<IExtensionFolders>().SingleInstance() 7 .WithParameter(new NamedParameter("paths", extensionLocations.ModuleLocations)); 8 builder.RegisterType<CoreModuleFolders>().As<IExtensionFolders>().SingleInstance() 9 .WithParameter(new NamedParameter("paths", extensionLocations.CoreLocations)); 10 builder.RegisterType<ThemeFolders>().As<IExtensionFolders>().SingleInstance() 11 .WithParameter(new NamedParameter("paths", extensionLocations.ThemeLocations)); 12 13 builder.RegisterType<CoreExtensionLoader>().As<IExtensionLoader>().SingleInstance(); 14 builder.RegisterType<ReferencedExtensionLoader>().As<IExtensionLoader>().SingleInstance(); 15 builder.RegisterType<PrecompiledExtensionLoader>().As<IExtensionLoader>().SingleInstance(); 16 builder.RegisterType<DynamicExtensionLoader>().As<IExtensionLoader>().SingleInstance(); 17 builder.RegisterType<RawThemeExtensionLoader>().As<IExtensionLoader>().SingleInstance(); 18 }
这里需要注意的是,除了以上的Loader外,这里还有一个Raw Theme Extension Loader。
接下来看Folder是如何工作的:
三个Folder的实现可以说是一致的,都是通过ExtensionHarvester去获取一个ExtensionDescriptior列表:
1 public IEnumerable<ExtensionDescriptor> AvailableExtensions() { 2 return _extensionHarvester.HarvestExtensions(_paths, DefaultExtensionTypes.Module, "Module.txt", false/*isManifestOptional*/); 3 }
仅仅是路径和文件名称(Module.txt和Theme.txt)不同。所以可以这样说,模块和主题的搜索工作是通过ExtensionHarvester完成的。
1 public IEnumerable<ExtensionDescriptor> HarvestExtensions(IEnumerable<string> paths, string extensionType, string manifestName, bool manifestIsOptional) { 2 return paths 3 .SelectMany(path => HarvestExtensions(path, extensionType, manifestName, manifestIsOptional)) 4 .ToList(); 5 } 6 private IEnumerable<ExtensionDescriptor> HarvestExtensions(string path, string extensionType, string manifestName, bool manifestIsOptional) { 7 string key = string.Format("{0}-{1}-{2}", path, manifestName, extensionType); 8 return _cacheManager.Get(key, true, ctx => { 9 if (!DisableMonitoring) { 10 Logger.Debug("Monitoring virtual path \"{0}\"", path); 11 ctx.Monitor(_webSiteFolder.WhenPathChanges(path)); 12 } 13 return AvailableExtensionsInFolder(path, extensionType, manifestName, manifestIsOptional).ToReadOnlyCollection(); 14 }); 15 }
从上面代码可以看出Harvester内部还使用了缓存机制,以路径、文件名称和类型(模块还是主题)来作为关键字。它缓存的内容是当前目录下的一个拓展描述列表。
描述信息包括:
1 public string Location { get; set; } 2 public string Id { get; set; } 3 public string VirtualPath { get { return Location + "/" + Id; } } 4 public string ExtensionType { get; set; } 5 public string Name { get; set; } 6 public string Path { get; set; } 7 public string Description { get; set; } 8 public string Version { get; set; } 9 public string OrchardVersion { get; set; } 10 public string Author { get; set; } 11 public string WebSite { get; set; } 12 public string Tags { get; set; } 13 public string AntiForgery { get; set; } 14 public string Zones { get; set; } 15 public string BaseTheme { get; set; } 16 public string SessionState { get; set; } 17 public LifecycleStatus LifecycleStatus { get; set; } 18 19 public IEnumerable<FeatureDescriptor> Features { get; set; }