public override void ExtensionActivated(ExtensionLoadingContext ctx, ExtensionDescriptor extension) { if (_reloadWorkaround.AppDomainRestartNeeded) { Logger.Information("ExtensionActivated: Module \"{0}\" has changed, forcing AppDomain restart", extension.Id); ctx.RestartAppDomain = _reloadWorkaround.AppDomainRestartNeeded; } }
public override ExtensionProbeEntry Probe(ExtensionDescriptor descriptor) { if (Disabled) return null; if (descriptor.Location == "~/Themes") { string projectPath = _virtualPathProvider.Combine(descriptor.Location, descriptor.Id, descriptor.Id + ".csproj"); // ignore themes including a .csproj in this loader if ( _virtualPathProvider.FileExists(projectPath) ) { return null; } var assemblyPath = _virtualPathProvider.Combine(descriptor.Location, descriptor.Id, "bin", descriptor.Id + ".dll"); // ignore themes with /bin in this loader if ( _virtualPathProvider.FileExists(assemblyPath) ) return null; return new ExtensionProbeEntry { Descriptor = descriptor, Loader = this, VirtualPath = "~/Theme/" + descriptor.Id, VirtualPathDependencies = Enumerable.Empty<string>(), }; } return null; }
public ExtensionEntry Load(ExtensionDescriptor descriptor) { var dependency = _dependenciesFolder.GetDescriptor(descriptor.Id); if (dependency != null && dependency.LoaderName == this.Name) { return LoadWorker(descriptor); } return null; }
protected override ExtensionEntry LoadWorker(ExtensionDescriptor descriptor) { if (Disabled) return null; Logger.Information("Loaded no-code theme \"{0}\"", descriptor.Name); return new ExtensionEntry { Descriptor = descriptor, Assembly = GetType().Assembly, ExportedTypes = new Type[0] }; }
public override ExtensionProbeEntry Probe(ExtensionDescriptor descriptor) { if (Disabled) return null; if (descriptor.Location == "~/Core") { return new ExtensionProbeEntry { Descriptor = descriptor, Loader = this, Priority = 100, // Higher priority because assemblies in ~/bin always take precedence VirtualPath = "~/Core/" + descriptor.Id, VirtualPathDependencies = Enumerable.Empty<string>(), }; } return null; }
public override ExtensionProbeEntry Probe(ExtensionDescriptor 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, // Higher priority because assemblies in ~/bin always take precedence VirtualPath = assemblyPath, VirtualPathDependencies = new[] { assemblyPath }, }; }
public override void ExtensionActivated(ExtensionLoadingContext ctx, ExtensionDescriptor extension) { string sourceFileName = _virtualPathProvider.MapPath(GetAssemblyPath(extension)); // Copy the assembly if it doesn't exist or if it is older than the source file. bool copyAssembly = !_assemblyProbingFolder.AssemblyExists(extension.Id) || File.GetLastWriteTimeUtc(sourceFileName) > _assemblyProbingFolder.GetAssemblyDateTimeUtc(extension.Id); if (copyAssembly) { ctx.CopyActions.Add(() => _assemblyProbingFolder.StoreAssembly(extension.Id, sourceFileName)); // We need to restart the appDomain if the assembly is loaded if (_hostEnvironment.IsAssemblyLoaded(extension.Id)) { Logger.Information("ExtensionRemoved: Module \"{0}\" is activated with newer file and its assembly is loaded, forcing AppDomain restart", extension.Id); ctx.RestartAppDomain = true; } } }
protected override ExtensionEntry LoadWorker(ExtensionDescriptor descriptor) { if (Disabled) return null; var assembly = _assemblyLoader.Load(CoreAssemblyName); if (assembly == null) { Logger.Error("Core modules cannot be activated because assembly '{0}' could not be loaded", CoreAssemblyName); return null; } Logger.Information("Loaded core module \"{0}\": assembly name=\"{1}\"", descriptor.Name, assembly.FullName); return new ExtensionEntry { Descriptor = descriptor, Assembly = assembly, ExportedTypes = assembly.GetExportedTypes().Where(x => IsTypeFromModule(x, descriptor)) }; }
protected override ExtensionEntry LoadWorker(ExtensionDescriptor descriptor) { if (Disabled) return null; Logger.Information("Start loading pre-compiled extension \"{0}\"", descriptor.Name); var assembly = _assemblyProbingFolder.LoadAssembly(descriptor.Id); if (assembly == null) return null; Logger.Information("Done loading pre-compiled extension \"{0}\": assembly name=\"{1}\"", descriptor.Name, assembly.FullName); return new ExtensionEntry { Descriptor = descriptor, Assembly = assembly, ExportedTypes = assembly.GetExportedTypes() }; }
public override IEnumerable<ExtensionReferenceProbeEntry> ProbeReferences(ExtensionDescriptor descriptor) { if (Disabled) return Enumerable.Empty<ExtensionReferenceProbeEntry>(); Logger.Information("Probing references for module '{0}'", descriptor.Id); var assemblyPath = GetAssemblyPath(descriptor); if (assemblyPath == null) return Enumerable.Empty<ExtensionReferenceProbeEntry>(); var result = _virtualPathProvider .ListFiles(_virtualPathProvider.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("Done probing references for module '{0}'", descriptor.Id); return result; }
public override ExtensionProbeEntry Probe(ExtensionDescriptor descriptor) { if (Disabled) return null; Logger.Information("Probing for module '{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("Done probing for module '{0}'", descriptor.Id); return result; }
private IEnumerable<IViewEngine> CreateThemeViewEngines(ExtensionDescriptor theme) { var themeLocation = theme.Location + "/" + theme.Id; var themeParams = new CreateThemeViewEngineParams {VirtualPath = themeLocation}; return _viewEngineProviders.Select(vep => vep.CreateThemeViewEngine(themeParams)); }
public ExtensionProbeEntry Probe(ExtensionDescriptor descriptor) { return new ExtensionProbeEntry { Descriptor = descriptor, Loader = this }; }
private IEnumerable<ExtensionDescriptor> GetBaseThemes(ExtensionDescriptor themeExtension) { if (themeExtension.Id.Equals("TheAdmin", StringComparison.OrdinalIgnoreCase)) { // Special case: conceptually, the base themes of "TheAdmin" is the list of all // enabled themes. This is so that any enabled theme can have controller/action/views // in the Admin of the site. return _extensionManager .EnabledFeatures(_shellDescriptor) .Reverse() // reverse from (C <= B <= A) to (A => B => C) .Select(fd => fd.Extension) .Where(fd => DefaultExtensionTypes.IsTheme(fd.ExtensionType)); } else { var availableFeatures = _extensionManager.AvailableFeatures(); var list = new List<ExtensionDescriptor>(); while(true) { if (themeExtension == null) break; if (String.IsNullOrEmpty(themeExtension.BaseTheme)) break; var baseFeature = availableFeatures.FirstOrDefault(fd => fd.Id == themeExtension.BaseTheme); if (baseFeature == null) { Logger.Error("Base theme '{0}' of theme '{1}' not found in list of features", themeExtension.BaseTheme, themeExtension.Id); break; } // Protect against potential infinite loop if (list.Contains(baseFeature.Extension)) { Logger.Error("Base theme '{0}' of theme '{1}' ignored, as it seems there is recursion in base themes", themeExtension.BaseTheme, themeExtension.Id); break; } list.Add(baseFeature.Extension); themeExtension = baseFeature.Extension; } return list; } }
public void ExtensionDeactivated(ExtensionLoadingContext ctx, ExtensionDescriptor extension) { throw new NotImplementedException(); }
public override void ExtensionDeactivated(ExtensionLoadingContext ctx, ExtensionDescriptor extension) { DeleteAssembly(ctx, extension.Id); }
private void ProcessExtension(ExtensionLoadingContext context, ExtensionDescriptor extension) { var extensionProbes = context.AvailableExtensionsProbes.ContainsKey(extension.Id) ? context.AvailableExtensionsProbes[extension.Id] : Enumerable.Empty<ExtensionProbeEntry>(); // materializes the list extensionProbes = extensionProbes.ToArray(); if (Logger.IsEnabled(LogLevel.Debug)) { Logger.Debug("Loaders for extension \"{0}\": ", extension.Id); foreach (var probe in extensionProbes) { Logger.Debug(" Loader: {0}", probe.Loader.Name); Logger.Debug(" VirtualPath: {0}", probe.VirtualPath); Logger.Debug(" VirtualPathDependencies: {0}", string.Join(", ", probe.VirtualPathDependencies)); } } var moduleReferences = context.AvailableExtensions .Where(e => context.ReferencesByModule.ContainsKey(extension.Id) && context.ReferencesByModule[extension.Id].Any(r => StringComparer.OrdinalIgnoreCase.Equals(e.Id, r.Name))) .ToList(); var processedModuleReferences = moduleReferences .Where(e => context.ProcessedExtensions.ContainsKey(e.Id)) .Select(e => context.ProcessedExtensions[e.Id]) .ToList(); var activatedExtension = extensionProbes.FirstOrDefault( e => e.Loader.IsCompatibleWithModuleReferences(extension, processedModuleReferences) ); var previousDependency = context.PreviousDependencies.FirstOrDefault( d => StringComparer.OrdinalIgnoreCase.Equals(d.Name, extension.Id) ); if (activatedExtension == null) { Logger.Warning("No loader found for extension \"{0}\"!", extension.Id); } var references = ProcessExtensionReferences(context, activatedExtension); foreach (var loader in _loaders) { if (activatedExtension != null && activatedExtension.Loader.Name == loader.Name) { Logger.Information("Activating extension \"{0}\" with loader \"{1}\"", activatedExtension.Descriptor.Id, loader.Name); loader.ExtensionActivated(context, extension); } else if (previousDependency != null && previousDependency.LoaderName == loader.Name) { Logger.Information("Deactivating extension \"{0}\" from loader \"{1}\"", previousDependency.Name, loader.Name); loader.ExtensionDeactivated(context, extension); } } if (activatedExtension != null) { context.NewDependencies.Add(new DependencyDescriptor { Name = extension.Id, LoaderName = activatedExtension.Loader.Name, VirtualPath = activatedExtension.VirtualPath, References = references }); } // Keep track of which loader we use for every extension // This will be needed for processing references from other dependent extensions context.ProcessedExtensions.Add(extension.Id, activatedExtension); }
private IViewEngine ShallowEngines(ExtensionDescriptor theme) { //return _configuredEnginesCache.BindShallowEngines(theme.ThemeName, () => new ViewEngineCollectionWrapper(_viewEngineProviders.Select(vep => vep.CreateBareViewEngine()))); return DeepEngines(theme); }
public override void ExtensionDeactivated(ExtensionLoadingContext ctx, ExtensionDescriptor extension) { if (_assemblyProbingFolder.AssemblyExists(extension.Id)) { ctx.DeleteActions.Add( () => { Logger.Information("ExtensionDeactivated: Deleting assembly \"{0}\" from probing directory", extension.Id); _assemblyProbingFolder.DeleteAssembly(extension.Id); }); // We need to restart the appDomain if the assembly is loaded if (_hostEnvironment.IsAssemblyLoaded(extension.Id)) { Logger.Information("ExtensionDeactivated: Module \"{0}\" is deactivated and its assembly is loaded, forcing AppDomain restart", extension.Id); ctx.RestartAppDomain = true; } } }
public ExtensionEntry Load(ExtensionDescriptor descriptor) { return new ExtensionEntry { Descriptor = descriptor, ExportedTypes = new[] { typeof(Alpha), typeof(Beta), typeof(Phi) } }; }
protected override ExtensionEntry LoadWorker(ExtensionDescriptor descriptor) { if (Disabled) return null; var assembly = _buildManager.GetReferencedAssembly(descriptor.Id); if (assembly == null) return null; Logger.Information("Loaded referenced extension \"{0}\": assembly name=\"{1}\"", descriptor.Name, assembly.FullName); return new ExtensionEntry { Descriptor = descriptor, Assembly = assembly, ExportedTypes = assembly.GetExportedTypes() }; }
private IViewEngine DeepEngines(ExtensionDescriptor theme) { return _configuredEnginesCache.BindDeepEngines(theme.Id, () => { // The order for searching for views is: // 1. Current "theme" // 2. Base themes of the current theme (in "base" order) // 3. Active features from modules in dependency order var engines = Enumerable.Empty<IViewEngine>(); // 1. current theme engines = engines.Concat(CreateThemeViewEngines(theme)); // 2. Base themes of the current theme (in "base" order) engines = GetBaseThemes(theme).Aggregate(engines, (current, baseTheme) => current.Concat(CreateThemeViewEngines(baseTheme))); // 3. Active features from modules in dependency order var enabledModules = _extensionManager.EnabledFeatures(_shellDescriptor) .Reverse() // reverse from (C <= B <= A) to (A => B => C) .Where(fd => DefaultExtensionTypes.IsModule(fd.Extension.ExtensionType)); 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 static bool IsTypeFromModule(Type type, ExtensionDescriptor descriptor) { return (type.Namespace + ".").StartsWith(CoreAssemblyName + "." + descriptor.Id + "."); }
public IEnumerable<ExtensionDescriptor> AvailableExtensions() { var ext = new ExtensionDescriptor { Id = "Coevery.Framework" }; ext.Features = new[] { new FeatureDescriptor { Extension = ext, Id = ext.Id } }; yield return ext; }
public bool IsCompatibleWithModuleReferences(ExtensionDescriptor extension, IEnumerable<ExtensionProbeEntry> references) { throw new NotImplementedException(); }
public string GetAssemblyPath(ExtensionDescriptor descriptor) { var assemblyPath = _virtualPathProvider.Combine(descriptor.Location, descriptor.Id, "bin", descriptor.Id + ".dll"); if (!_virtualPathProvider.FileExists(assemblyPath)) return null; return assemblyPath; }
public void Monitor(ExtensionDescriptor extension, Action<IVolatileToken> monitor) { }
public override bool IsCompatibleWithModuleReferences(ExtensionDescriptor extension, IEnumerable<ExtensionProbeEntry> references) { // A pre-compiled module is _not_ compatible with a dynamically loaded module // because a pre-compiled module usually references a pre-compiled assembly binary // which will have a different identity (i.e. name) from the dynamic module. bool result = references.All(r => r.Loader.GetType() != typeof(DynamicExtensionLoader)); if (!result) { Logger.Information("Extension \"{0}\" will not be loaded as pre-compiled extension because one or more referenced extension is dynamically compiled", extension.Id); } return result; }
public IEnumerable<ExtensionReferenceProbeEntry> ProbeReferences(ExtensionDescriptor extensionDescriptor) { throw new NotImplementedException(); }
public override void Monitor(ExtensionDescriptor descriptor, Action<IVolatileToken> monitor) { if (Disabled) return; if (DisableMonitoring) return; // If the assembly exists, monitor it string assemblyPath = GetAssemblyPath(descriptor); if (assemblyPath != null) { Logger.Debug("Monitoring virtual path \"{0}\"", assemblyPath); monitor(_virtualPathMonitor.WhenPathChanges(assemblyPath)); return; } // If the assembly doesn't exist, we monitor the containing "bin" folder, as the assembly // may exist later if it is recompiled in Visual Studio for example, and we need to // detect that as a change of configuration. var assemblyDirectory = _virtualPathProvider.Combine(descriptor.Location, descriptor.Id, "bin"); if (_virtualPathProvider.DirectoryExists(assemblyDirectory)) { Logger.Debug("Monitoring virtual path \"{0}\"", assemblyDirectory); monitor(_virtualPathMonitor.WhenPathChanges(assemblyDirectory)); } }