/// <summary>
        /// 探测。
        /// </summary>
        /// <param name="descriptor">扩展描述符条目。</param>
        /// <returns>扩展探测条目。</returns>
        public override ExtensionProbeEntry Probe(ExtensionDescriptorEntry descriptor)
        {
            if (Disabled)
                return null;

            if (descriptor.Location != "~/Themes")
                return null;
            var projectPath = _virtualPathProvider.Combine(descriptor.Location, descriptor.Id,
                descriptor.Id + ".csproj");

            //如果项目文件不存在则忽略主题
            if (_virtualPathProvider.FileExists(projectPath))
            {
                return null;
            }

            var assemblyPath = _virtualPathProvider.Combine(descriptor.Location, descriptor.Id, "bin",
                descriptor.Id + ".dll");

            //如果主题包含dll文件则忽略
            if (_virtualPathProvider.FileExists(assemblyPath))
                return null;

            return new ExtensionProbeEntry
            {
                Descriptor = descriptor,
                Loader = this,
                VirtualPath = "~/Theme/" + descriptor.Id,
                VirtualPathDependencies = Enumerable.Empty<string>(),
            };
        }
        /// <summary>
        /// 探测引用。
        /// </summary>
        /// <param name="descriptor">扩展描述符条目。</param>
        /// <returns>扩展音域探测条目集合。</returns>
        public override IEnumerable<ExtensionReferenceProbeEntry> ProbeReferences(ExtensionDescriptorEntry descriptor)
        {
            if (Disabled)
                return Enumerable.Empty<ExtensionReferenceProbeEntry>();

            Logger.Information("探测模块 '{0}' 的引用信息", descriptor.Id);

            var assemblyPath = GetAssemblyPath(descriptor);
            if (assemblyPath == null)
                return Enumerable.Empty<ExtensionReferenceProbeEntry>();

            var result = _applicationFolder
                .ListFiles(_applicationFolder.GetDirectoryName(assemblyPath))
                .Where(s => StringComparer.OrdinalIgnoreCase.Equals(Path.GetExtension(s), ".dll"))
                .Where(s => !StringComparer.OrdinalIgnoreCase.Equals(Path.GetFileNameWithoutExtension(s), descriptor.Id))
                .Select(path => new ExtensionReferenceProbeEntry
                {
                    Descriptor = descriptor,
                    Loader = this,
                    Name = Path.GetFileNameWithoutExtension(path),
                    VirtualPath = path
                })
                .ToList();

            Logger.Information("完成模块 '{0}' 的引用探测", descriptor.Id);
            return result;
        }
        /// <summary>
        /// 探测。
        /// </summary>
        /// <param name="descriptor">扩展描述符条目。</param>
        /// <returns>扩展探测条目。</returns>
        public override ExtensionProbeEntry Probe(ExtensionDescriptorEntry descriptor)
        {
            if (Disabled)
                return null;

            var assembly = _buildManager.GetReferencedAssembly(descriptor.Id);
            if (assembly == null)
                return null;

            var assemblyPath = _virtualPathProvider.Combine("~/bin", descriptor.Id + ".dll");

            return new ExtensionProbeEntry
            {
                Descriptor = descriptor,
                Loader = this,
                Priority = 100, //更高的优先级,因为在~/bin中的程序集总是优先
                VirtualPath = assemblyPath,
                VirtualPathDependencies = new[] { assemblyPath },
            };
        }
        public static void Parse(string text, ExtensionDescriptorEntry entry, ILogger logger, Localizer localizer)
        {
            _logger = logger;
            _localizer = localizer;

            var descriptor = entry.Descriptor;
            var manifest = ParseManifest(text, (key, value) =>
            {
                descriptor[key] = value;
            });

            descriptor.Name = GetValue(manifest, NameSection);
            descriptor.Path = GetValue(manifest, PathSection);
            descriptor.Description = GetValue(manifest, DescriptionSection);
            descriptor.Version = GetExtensionVersion(entry.Id, manifest);
            descriptor.KernelVersion = GetKernelVersion(entry.Id, manifest);
            descriptor.Author = GetValue(manifest, AuthorSection);
            descriptor.WebSite = GetValue(manifest, WebsiteSection);
            descriptor.Tags = GetValue(manifest, TagsSection);
            //            descriptor.Runtime = GetRuntime(manifest);

            descriptor.Features = GetFeaturesForExtension(manifest, entry);
        }
        /// <summary>
        /// 扩展激活。
        /// </summary>
        /// <param name="context">扩展装载上下文。</param>
        /// <param name="descriptor">扩展描述符条目。</param>
        public override void ExtensionActivated(ExtensionLoadingContext context, ExtensionDescriptorEntry descriptor)
        {
            var sourceFileName = _applicationFolder.MapPath(GetAssemblyPath(descriptor));

            //如果程序集文件不存在或者比新的旧则复制新的程序集文件到依赖目录。
            var copyAssembly =
                !_assemblyProbingFolder.AssemblyExists(new AssemblyDescriptor(descriptor.Id)) ||
                File.GetLastWriteTimeUtc(sourceFileName) > _assemblyProbingFolder.GetAssemblyDateTimeUtc(new AssemblyDescriptor(descriptor.Id));

            if (!copyAssembly)
                return;
            context.CopyActions.Add(() => _assemblyProbingFolder.StoreAssembly(new AssemblyDescriptor(descriptor.Id), sourceFileName));

            //如果程序集已经被加载,需要重新启动AppDomain
            if (!_hostEnvironment.IsAssemblyLoaded(descriptor.Id))
                return;
            Logger.Information("ExtensionRemoved: 模块 \"{0}\" 激活新的程序集文件加载,迫使AppDomain重启", descriptor.Id);
            context.RestartAppDomain = true;
        }
示例#6
0
 private static ExtensionDescriptorEntry GetExtensionDescriptorEntry(string id, string type, string localtion)
 {
     var extension = new ExtensionDescriptorEntry(new ExtensionDescriptor(), id, type, localtion);
     extension.Descriptor.Features = new[]
     {
         new FeatureDescriptor
         {
             Id = extension.Id,
             Extension = extension
         }
     };
     return extension;
 }
        /// <summary>
        /// 装载工作。
        /// </summary>
        /// <param name="descriptor">扩展描述符条目。</param>
        /// <returns>扩展条目。</returns>
        protected override ExtensionEntry LoadWorker(ExtensionDescriptorEntry descriptor)
        {
            if (Disabled)
                return null;

            Logger.Information("加载没有代码的主题 \"{0}\"", descriptor.Descriptor.Name);

            return new ExtensionEntry
            {
                Descriptor = descriptor,
                Assembly = GetType().Assembly,
                ExportedTypes = new Type[0]
            };
        }
 private IViewEngine ShallowEngines(ExtensionDescriptorEntry theme)
 {
     return DeepEngines(theme);
 }
        private IViewEngine DeepEngines(ExtensionDescriptorEntry theme)
        {
            return _configuredEnginesCache.BindDeepEngines(theme.Id, () =>
            {
                // 搜索视图顺序:
                // 1. 当前主图
                // 2. 基础主题
                // 3. 来自模块激活功能依赖排序

                var engines = Enumerable.Empty<IViewEngine>();
                // 1. 当前主题
                engines = engines.Concat(CreateThemeViewEngines(theme));

                // 2. 基础主题
                engines = GetBaseThemes(theme).Aggregate(engines, (current, baseTheme) => current.Concat(CreateThemeViewEngines(baseTheme)));

                // 3. 来自模块激活功能依赖排序
                var enabledModules = _extensionManager.EnabledFeatures(_shellDescriptor)
                    .Reverse()  // reverse from (C <= B <= A) to (A => B => C)
                    .Where(fd => DefaultExtensionTypes.IsModule(fd.Extension.ExtensionType)).ToArray();

                var allLocations = enabledModules.Concat(enabledModules)
                    .Select(fd => fd.Extension.Location + "/" + fd.Extension.Id)
                    .Distinct(StringComparer.OrdinalIgnoreCase)
                    .ToList();

                var moduleParams = new CreateModulesViewEngineParams { VirtualPaths = allLocations };
                engines = engines.Concat(_viewEngineProviders.Select(vep => vep.CreateModulesViewEngine(moduleParams)));

                return new ViewEngineCollectionWrapper(engines);
            });
        }
 private ExtensionEntry BuildEntry(ExtensionDescriptorEntry descriptor)
 {
     var entry = _loaders.Value.Select(loader => loader.Load(descriptor)).FirstOrDefault(i => i != null);
     if (entry == null)
         Logger.Warning("没有发现适合扩展 \"{0}\" 的装载机", descriptor.Id);
     return entry;
 }
        private ExtensionDescriptorEntry GetExtensionDescriptor(string locationPath, string extensionId, string extensionType, string manifestPath, bool manifestIsOptional)
        {
            return _cacheManager.Get(manifestPath, context =>
            {
                if (!DisableMonitoring)
                {
                    Logger.Debug("监控虚拟路径 \"{0}\"", manifestPath);
                    context.Monitor(_applicationFolder.WhenPathChanges(manifestPath));
                }

                var manifestText = _applicationFolder.ReadFile(manifestPath);
                if (manifestText == null)
                {
                    if (manifestIsOptional)
                    {
                        manifestText = string.Format("Id: {0}", extensionId);
                    }
                    else
                    {
                        return null;
                    }
                }

                var entry = new ExtensionDescriptorEntry(new ExtensionDescriptor(), extensionId, extensionType, locationPath);
                ExtensionDescriptorSerializer.Parse(manifestText, entry, Logger, T);
                return entry;
            });
        }
 public string GetAssemblyPath(ExtensionDescriptorEntry descriptor)
 {
     var assemblyPath = _applicationFolder.Combine(descriptor.Location, descriptor.Id, "bin",
                                                     descriptor.Id + ".dll");
     return !_applicationFolder.FileExists(assemblyPath) ? null : assemblyPath;
 }
        /// <summary>
        /// 装载工作。
        /// </summary>
        /// <param name="descriptor">扩展描述符条目。</param>
        /// <returns>扩展条目。</returns>
        protected override ExtensionEntry LoadWorker(ExtensionDescriptorEntry descriptor)
        {
            if (Disabled)
                return null;

            Logger.Information("开始加载预编译的扩展 \"{0}\"", descriptor.Descriptor.Name);

            var assembly = _assemblyProbingFolder.LoadAssembly(new AssemblyDescriptor(descriptor.Id));
            if (assembly == null)
                return null;

            Logger.Information("完成加载预编译的扩展 \"{0}\": 程序集名称=\"{1}\"", descriptor.Descriptor.Name, assembly.FullName);

            return new ExtensionEntry
            {
                Descriptor = descriptor,
                Assembly = assembly,
                ExportedTypes = assembly.GetTypes()
            };
        }
        /// <summary>
        /// 监控扩展。
        /// </summary>
        /// <param name="descriptor">扩展描述符条目。</param>
        /// <param name="monitor">监控动作。</param>
        public override void Monitor(ExtensionDescriptorEntry descriptor, Action<IVolatileToken> monitor)
        {
            if (Disabled)
                return;

            if (DisableMonitoring)
                return;

            //如果程序集文件存在则进行监控。
            var assemblyPath = GetAssemblyPath(descriptor);
            if (assemblyPath != null)
            {
                Logger.Debug("监控虚拟路径 \"{0}\"", assemblyPath);
                monitor(_applicationFolder.WhenPathChanges(assemblyPath));
                return;
            }

            //如果该组件不存在,我们监测含有“bin”文件夹后,如果是在Visual Studio中,例如重新编译的组件可能存在,我们需要改变配置检测。
            var assemblyDirectory = _applicationFolder.Combine(descriptor.Location, descriptor.Id, "bin");
            if (!_applicationFolder.DirectoryExists(assemblyDirectory))
                return;
            Logger.Debug("监控虚拟路径 \"{0}\"", assemblyDirectory);
            monitor(_applicationFolder.WhenPathChanges(assemblyDirectory));
        }
        /// <summary>
        /// 扩展停用。
        /// </summary>
        /// <param name="context">扩展装载上下文。</param>
        /// <param name="descriptor">扩展描述符条目。</param>
        public override void ExtensionDeactivated(ExtensionLoadingContext context, ExtensionDescriptorEntry descriptor)
        {
            if (!_assemblyProbingFolder.AssemblyExists(new AssemblyDescriptor(descriptor.Id)))
                return;

            context.DeleteActions.Add(
                () =>
                {
                    Logger.Information("ExtensionDeactivated: 删除在探测目录中的程序集 \"{0}\"", descriptor.Id);
                    _assemblyProbingFolder.DeleteAssembly(descriptor.Id);
                });

            //如果程序集已经被加载,需要重新启动AppDomain
            if (!_hostEnvironment.IsAssemblyLoaded(descriptor.Id))
                return;
            Logger.Information("ExtensionDeactivated: 模块 \"{0}\" 已停用,它的程序集已经被加载,迫使AppDomain重启", descriptor.Id);
            context.RestartAppDomain = true;
        }
 /// <summary>
 /// 初始化一个新的扩展描述符条目过滤器上下文。
 /// </summary>
 /// <param name="entry">扩展描述符条目。</param>
 public ExtensionDescriptorEntryFilterContext(ExtensionDescriptorEntry entry)
 {
     entry.NotNull("entry");
     Entry = entry;
     Valid = true;
 }
 private IEnumerable<IViewEngine> CreateThemeViewEngines(ExtensionDescriptorEntry theme)
 {
     var themeLocation = theme.Location + "/" + theme.Id;
     var themeParams = new CreateThemeViewEngineParams { VirtualPath = themeLocation };
     return _viewEngineProviders.Select(vep => vep.CreateThemeViewEngine(themeParams));
 }
 /// <summary>
 /// 探测。
 /// </summary>
 /// <param name="descriptor">扩展描述符条目。</param>
 /// <returns>扩展探测条目。</returns>
 public abstract ExtensionProbeEntry Probe(ExtensionDescriptorEntry descriptor);
        private IEnumerable<ExtensionDescriptorEntry> GetBaseThemes(ExtensionDescriptorEntry themeExtension)
        {
            //TODO:这边需要重新考虑
            /*if (themeExtension.Id.Equals("TheAdmin", StringComparison.OrdinalIgnoreCase))
            {
                return _extensionManager
                    .EnabledFeatures(_shellDescriptor)
                    .Reverse()
                    .Select(fd => fd.Extension)
                    .Where(fd => DefaultExtensionTypes.IsTheme(fd.ExtensionType));
            }*/
            var availableFeatures = _extensionManager.AvailableFeatures().ToArray();
            var list = new List<ExtensionDescriptorEntry>();
            while (true)
            {
                if (themeExtension == null)
                    break;

                if (String.IsNullOrEmpty(themeExtension.Descriptor.GetBaseTheme()))
                    break;

                var baseFeature = availableFeatures.FirstOrDefault(fd => fd.Id == themeExtension.Descriptor.GetBaseTheme());
                if (baseFeature == null)
                {
                    Logger.Error("在 '{1}' 功能列表中找不到基础主题 '{0}'", themeExtension.Descriptor.GetBaseTheme(), themeExtension.Id);
                    break;
                }

                //防止潜在的无限循环
                if (list.Contains(baseFeature.Extension))
                {
                    Logger.Error("主题 '{1}' 是基础主题 '{0}' 所以被忽略", themeExtension.Descriptor.GetBaseTheme(), themeExtension.Id);
                    break;
                }

                list.Add(baseFeature.Extension);

                themeExtension = baseFeature.Extension;
            }
            return list;
        }
 /// <summary>
 /// 装载扩展。
 /// </summary>
 /// <param name="descriptor">扩展描述符条目。</param>
 /// <returns>扩展条目。</returns>
 public ExtensionEntry Load(ExtensionDescriptorEntry descriptor)
 {
     var dependency = _dependenciesFolder.GetDescriptor(descriptor.Id);
     if (dependency != null && dependency.LoaderName == Name)
     {
         return LoadWorker(descriptor);
     }
     return null;
 }
 /// <summary>
 /// 扩展停用。
 /// </summary>
 /// <param name="context">扩展装载上下文。</param>
 /// <param name="descriptor">扩展描述符条目。</param>
 public virtual void ExtensionDeactivated(ExtensionLoadingContext context, ExtensionDescriptorEntry descriptor)
 {
 }
 /// <summary>
 /// 监控扩展。
 /// </summary>
 /// <param name="descriptor">扩展描述符条目。</param>
 /// <param name="monitor">监控动作。</param>
 public virtual void Monitor(ExtensionDescriptorEntry descriptor, Action<IVolatileToken> monitor)
 {
 }
        /*        private IEnumerable<KeyValuePair<AssemblyDescriptor, string>> GetModuleAssemblyPaths(ExtensionDescriptorEntry descriptor)
                {
                    if (descriptor.Descriptor == null || descriptor.Descriptor.Runtime == null || descriptor.Descriptor.Runtime.Assemblies == null)
                        return null;
                    return descriptor.Descriptor.Runtime.Assemblies.ToDictionary(i => i,
                        v => _applicationFolder.Combine(descriptor.Location, descriptor.Id, "bin", v.Name + ".dll"));
                }*/

        private string GetModuleAssemblyPath(ExtensionDescriptorEntry descriptor)
        {
            return _applicationFolder.Combine(descriptor.Location, descriptor.Id, "bin", descriptor.Id + ".dll");
        }
 /// <summary>
 /// 装载工作。
 /// </summary>
 /// <param name="descriptor">扩展描述符条目。</param>
 /// <returns>扩展条目。</returns>
 protected abstract ExtensionEntry LoadWorker(ExtensionDescriptorEntry descriptor);
        private static IEnumerable<FeatureDescriptor> GetFeaturesForExtension(IDictionary<string, string> manifest, ExtensionDescriptorEntry entry)
        {
            var featureDescriptors = new List<FeatureDescriptor>();

            var descriptor = entry.Descriptor;
            //默认特性
            var defaultFeature = new FeatureDescriptor
            {
                Id = entry.Id,
                Name = GetValue(manifest, FeatureNameSection) ?? descriptor.Name,
                Priority = GetValue(manifest, PrioritySection) != null ? int.Parse(GetValue(manifest, PrioritySection)) : 0,
                Description = GetValue(manifest, FeatureDescriptionSection) ?? GetValue(manifest, DescriptionSection) ?? string.Empty,
                Dependencies = ParseFeatureDependenciesEntry(GetValue(manifest, DependenciesSection)),
                Extension = entry,
                Category = GetValue(manifest, CategorySection)
            };

            featureDescriptors.Add(defaultFeature);

            //剩余特性
            var featuresText = GetValue(manifest, FeaturesSection);
            if (string.IsNullOrWhiteSpace(featuresText))
                return featureDescriptors;
            FeatureDescriptor featureDescriptor = null;
            using (var reader = new StringReader(featuresText))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    if (IsFeatureDeclaration(line))
                    {
                        if (featureDescriptor != null)
                        {
                            if (!featureDescriptor.Equals(defaultFeature))
                            {
                                featureDescriptors.Add(featureDescriptor);
                            }
                        }

                        var featureDeclaration = line.Split(new[] { ":" }, StringSplitOptions.RemoveEmptyEntries);
                        var featureDescriptorId = featureDeclaration[0].Trim();
                        if (string.Equals(featureDescriptorId, entry.Id, StringComparison.OrdinalIgnoreCase))
                        {
                            featureDescriptor = defaultFeature;
                            featureDescriptor.Name = descriptor.Name;
                        }
                        else
                        {
                            featureDescriptor = new FeatureDescriptor
                            {
                                Id = featureDescriptorId,
                                Extension = entry
                            };
                        }
                    }
                    else if (IsFeatureFieldDeclaration(line))
                    {
                        if (featureDescriptor != null)
                        {
                            var featureField = line.Split(new[] { ":" }, 2, StringSplitOptions.None);
                            var featureFieldLength = featureField.Length;
                            if (featureFieldLength != 2)
                                continue;
                            for (var i = 0; i < featureFieldLength; i++)
                            {
                                featureField[i] = featureField[i].Trim();
                            }

                            switch (featureField[0].ToLowerInvariant())
                            {
                                case NameSection:
                                    featureDescriptor.Name = featureField[1];
                                    break;

                                case DescriptionSection:
                                    featureDescriptor.Description = featureField[1];
                                    break;

                                case CategorySection:
                                    featureDescriptor.Category = featureField[1];
                                    break;

                                case PrioritySection:
                                    featureDescriptor.Priority = int.Parse(featureField[1]);
                                    break;

                                case DependenciesSection:
                                    featureDescriptor.Dependencies = ParseFeatureDependenciesEntry(featureField[1]);
                                    break;
                            }
                        }
                        else
                        {
                            var message = string.Format("行 {0} 在清单文件中被忽略,来自扩展 {1}", line, entry.Id);
                            throw new ArgumentException(message);
                        }
                    }
                    else
                    {
                        var message = string.Format("行 {0} 在清单文件中被忽略,来自扩展 {1}", line, entry.Id);
                        throw new ArgumentException(message);
                    }
                }

                if (featureDescriptor != null && !featureDescriptor.Equals(defaultFeature))
                    featureDescriptors.Add(featureDescriptor);
            }

            return featureDescriptors;
        }
 /// <summary>
 /// 探测引用。
 /// </summary>
 /// <param name="descriptor">扩展描述符条目。</param>
 /// <returns>扩展音域探测条目集合。</returns>
 public virtual IEnumerable<ExtensionReferenceProbeEntry> ProbeReferences(ExtensionDescriptorEntry descriptor)
 {
     return Enumerable.Empty<ExtensionReferenceProbeEntry>();
 }
        /// <summary>
        /// 装载工作。
        /// </summary>
        /// <param name="descriptor">扩展描述符条目。</param>
        /// <returns>扩展条目。</returns>
        protected override ExtensionEntry LoadWorker(ExtensionDescriptorEntry descriptor)
        {
            if (Disabled)
                return null;

            var assembly = _buildManager.GetReferencedAssembly(descriptor.Id);
            if (assembly == null)
                return null;

            Logger.Information("装载引用扩展 \"{0}\":程序集名称=\"{1}\"", descriptor.Descriptor.Name, assembly.FullName);

            return new ExtensionEntry
            {
                Descriptor = descriptor,
                Assembly = assembly,
                ExportedTypes = assembly.GetTypes()
            };
        }
 /// <summary>
 ///
 /// </summary>
 /// <param name="descriptor">扩展描述符条目。</param>
 /// <param name="references">扩展探测条目集合。</param>
 /// <returns></returns>
 public virtual bool IsCompatibleWithModuleReferences(ExtensionDescriptorEntry descriptor, IEnumerable<ExtensionProbeEntry> references)
 {
     return true;
 }
 /// <summary>
 /// 扩展停用。
 /// </summary>
 /// <param name="context">扩展装载上下文。</param>
 /// <param name="descriptor">扩展描述符条目。</param>
 public override void ExtensionDeactivated(ExtensionLoadingContext context, ExtensionDescriptorEntry descriptor)
 {
     DeleteAssembly(context, descriptor.Id);
 }
        /// <summary>
        /// 探测。
        /// </summary>
        /// <param name="descriptor">扩展描述符条目。</param>
        /// <returns>扩展探测条目。</returns>
        public override ExtensionProbeEntry Probe(ExtensionDescriptorEntry descriptor)
        {
            if (Disabled)
                return null;

            Logger.Information("探测模块 '{0}'", descriptor.Id);

            var assemblyPath = GetAssemblyPath(descriptor);
            if (assemblyPath == null)
                return null;

            var result = new ExtensionProbeEntry
            {
                Descriptor = descriptor,
                Loader = this,
                VirtualPath = assemblyPath,
                VirtualPathDependencies = new[] { assemblyPath },
            };

            Logger.Information("完成模块 '{0}' 探测", descriptor.Id);
            return result;
        }