diff --git a/src/Umbraco.Core/CoreBootManager.cs b/src/Umbraco.Core/CoreBootManager.cs index a6507632f8..f66ba91a69 100644 --- a/src/Umbraco.Core/CoreBootManager.cs +++ b/src/Umbraco.Core/CoreBootManager.cs @@ -98,7 +98,7 @@ namespace Umbraco.Core //create the plugin manager //TODO: this is currently a singleton but it would be better if it weren't. Unfortunately the only way to get // rid of this singleton would be to put it into IoC and then use the ServiceLocator pattern. - PluginManager.Current = PluginManager = new PluginManager(ServiceProvider, ApplicationCache.RuntimeCache, ProfilingLogger, true); + PluginManager.Current = PluginManager = new PluginManager(ApplicationCache.RuntimeCache, ProfilingLogger, true); //build up core IoC servoces ConfigureCoreServices(Container); diff --git a/src/Umbraco.Core/Plugins/PluginManager.cs b/src/Umbraco.Core/Plugins/PluginManager.cs index a9a3d02c72..d1f4d81cae 100644 --- a/src/Umbraco.Core/Plugins/PluginManager.cs +++ b/src/Umbraco.Core/Plugins/PluginManager.cs @@ -18,54 +18,55 @@ using File = System.IO.File; namespace Umbraco.Core.Plugins { - /// - /// Used to resolve all plugin types and cache them and is also used to instantiate plugin types + /// Resolves and caches all plugin types, and instanciates them. /// /// - /// - /// This class should be used to resolve all plugin types, the TypeFinder should not be used directly! - /// - /// This class can expose extension methods to resolve custom plugins - /// - /// Before this class resolves any plugins it checks if the hash has changed for the DLLs in the /bin folder, if it hasn't + /// This class should be used to resolve all plugin types, the TypeFinder should not be used directly!. + /// Before this class resolves any plugins it checks if the hash has changed for the DLLs in the /bin folder, if it hasn't /// it will use the cached resolved plugins that it has already found which means that no assembly scanning is necessary. This leads - /// to much faster startup times. + /// to much faster startup times. /// public class PluginManager { - /// - /// Creates a new PluginManager with an ApplicationContext instance which ensures that the plugin xml - /// file is cached temporarily until app startup completes. - /// - /// - /// - /// - /// - public PluginManager(IServiceProvider serviceProvider, IRuntimeCacheProvider runtimeCache, ProfilingLogger logger, bool detectChanges = true) - { - if (serviceProvider == null) throw new ArgumentNullException("serviceProvider"); - if (runtimeCache == null) throw new ArgumentNullException("runtimeCache"); - if (logger == null) throw new ArgumentNullException("logger"); + private const string CacheKey = "umbraco-plugins.list"; + private static object _instanceLocker = new object(); + private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(); + private static PluginManager _instance; + private static bool _hasInstance; + + private readonly IRuntimeCacheProvider _runtimeCache; + private readonly ProfilingLogger _logger; + private readonly string _tempFolder; + private readonly HashSet _types = new HashSet(); + private long _cachedAssembliesHash = -1; + private long _currentAssembliesHash = -1; + private IEnumerable _assemblies; + + /// + /// Initializes a new instance of the class. + /// + /// A runtime cache. + /// A logger + /// A value indicating whether to detect changes. + public PluginManager(IRuntimeCacheProvider runtimeCache, ProfilingLogger logger, bool detectChanges = true) + { + if (runtimeCache == null) throw new ArgumentNullException(nameof(runtimeCache)); + if (logger == null) throw new ArgumentNullException(nameof(logger)); - _serviceProvider = serviceProvider; _runtimeCache = runtimeCache; _logger = logger; + // create the temp folder if it doesn't exist _tempFolder = IOHelper.MapPath("~/App_Data/TEMP/PluginCache"); - //create the folder if it doesn't exist if (Directory.Exists(_tempFolder) == false) - { Directory.CreateDirectory(_tempFolder); - } var pluginListFile = GetPluginListFilePath(); - //this is a check for legacy changes, before we didn't store the TypeResolutionKind in the file which was a mistake, - //so we need to detect if the old file is there without this attribute, if it is then we delete it + // check for legacy changes: before, we didn't store the TypeResolutionKind in the file, which was a mistake, + // so we need to detect if the old file is there without this attribute, if it is then we delete it if (DetectLegacyPluginListFile()) - { File.Delete(pluginListFile); - } if (detectChanges) { @@ -75,7 +76,7 @@ namespace Umbraco.Core.Plugins //if they have changed, we need to write the new file if (RequiresRescanning) { - //if the hash has changed, clear out the persisted list no matter what, this will force + // if the hash has changed, clear out the persisted list no matter what, this will force // rescanning of all plugin types including lazy ones. // http://issues.umbraco.org/issue/U4-4789 File.Delete(pluginListFile); @@ -85,75 +86,65 @@ namespace Umbraco.Core.Plugins } else { - - //if the hash has changed, clear out the persisted list no matter what, this will force + // if the hash has changed, clear out the persisted list no matter what, this will force // rescanning of all plugin types including lazy ones. // http://issues.umbraco.org/issue/U4-4789 File.Delete(pluginListFile); - //always set to true if we're not detecting (generally only for testing) + // always set to true if we're not detecting (generally only for testing) RequiresRescanning = true; } } - private readonly IServiceProvider _serviceProvider; - private readonly IRuntimeCacheProvider _runtimeCache; - private readonly ProfilingLogger _logger; - private const string CacheKey = "umbraco-plugins.list"; - static PluginManager _resolver; - private readonly string _tempFolder; - private long _cachedAssembliesHash = -1; - private long _currentAssembliesHash = -1; - private static bool _initialized = false; - private static object _singletonLock = new object(); - /// - /// We will ensure that no matter what, only one of these is created, this is to ensure that caching always takes place + /// Gets the current plugin manager. /// /// - /// The setter is generally only used for unit tests + /// Ensures that no matter what, only one plugin manager is created, and thus proper caching always takes place. + /// The setter is generally only used for unit tests + when creating the master plugin manager in CoreBootManager. /// public static PluginManager Current { get { - return LazyInitializer.EnsureInitialized(ref _resolver, ref _initialized, ref _singletonLock, () => + return LazyInitializer.EnsureInitialized(ref _instance, ref _hasInstance, ref _instanceLocker, () => { - if (ApplicationContext.Current == null) + var appctx = ApplicationContext.Current; + var cacheProvider = appctx == null + ? new NullCacheProvider() + : appctx.ApplicationCache.RuntimeCache; + ProfilingLogger profilingLogger; + if (appctx == null) { var logger = LoggerResolver.HasCurrent ? LoggerResolver.Current.Logger : new DebugDiagnosticsLogger(); var profiler = ProfilerResolver.HasCurrent ? ProfilerResolver.Current.Profiler : new LogProfiler(logger); - return new PluginManager( - new ActivatorServiceProvider(), - new NullCacheProvider(), - new ProfilingLogger(logger, profiler)); + profilingLogger = new ProfilingLogger(logger, profiler); } - return new PluginManager( - new ActivatorServiceProvider(), - ApplicationContext.Current.ApplicationCache.RuntimeCache, - ApplicationContext.Current.ProfilingLogger); + else + { + profilingLogger = appctx.ProfilingLogger; + } + return new PluginManager(cacheProvider, profilingLogger); }); } - set + internal set { - _initialized = true; - _resolver = value; + _hasInstance = true; + _instance = value; } } #region Hash checking methods + /// + /// Gets a value indicating whether the assemblies in the /bin, app_code, global.asax, etc... have changed since they were last hashed. + /// + internal bool RequiresRescanning { get; } /// - /// Returns a bool if the assemblies in the /bin, app_code, global.asax, etc... have changed since they were last hashed. + /// Gets the currently cached hash value of the scanned assemblies in the /bin folder. /// - internal bool RequiresRescanning { get; private set; } - - /// - /// Returns the currently cached hash value of the scanned assemblies in the /bin folder. Returns 0 - /// if no cache is found. - /// - /// + /// The cached hash value, or 0 if no cache is found. internal long CachedAssembliesHash { get @@ -162,24 +153,22 @@ namespace Umbraco.Core.Plugins return _cachedAssembliesHash; var filePath = GetPluginHashFilePath(); - if (!File.Exists(filePath)) - return 0; + if (File.Exists(filePath) == false) return 0; + var hash = File.ReadAllText(filePath, Encoding.UTF8); - Int64 val; - if (Int64.TryParse(hash, out val)) - { - _cachedAssembliesHash = val; - return _cachedAssembliesHash; - } - //it could not parse for some reason so we'll return 0. - return 0; + + long val; + if (long.TryParse(hash, out val) == false) return 0; + + _cachedAssembliesHash = val; + return _cachedAssembliesHash; } } /// - /// Returns the current assemblies hash based on creating a hash from the assemblies in the /bin + /// Gets the current assemblies hash based on creating a hash from the assemblies in the /bin folder. /// - /// + /// The current hash. internal long CurrentAssembliesHash { get @@ -190,23 +179,23 @@ namespace Umbraco.Core.Plugins _currentAssembliesHash = GetFileHash( new List> { - //add the bin folder and everything in it + // add the bin folder and everything in it new Tuple(new DirectoryInfo(IOHelper.MapPath(SystemDirectories.Bin)), false), - //add the app code folder and everything in it + // add the app code folder and everything in it new Tuple(new DirectoryInfo(IOHelper.MapPath("~/App_Code")), false), - //add the global.asax (the app domain also monitors this, if it changes will do a full restart) + // add the global.asax (the app domain also monitors this, if it changes will do a full restart) new Tuple(new FileInfo(IOHelper.MapPath("~/global.asax")), false), - - //add the trees.config - use the contents to create the has since this gets resaved on every app startup! + // add the trees.config - use the contents to create the has since this gets resaved on every app startup! new Tuple(new FileInfo(IOHelper.MapPath(SystemDirectories.Config + "/trees.config")), true) }, _logger ); + return _currentAssembliesHash; } } /// - /// Writes the assembly hash file + /// Writes the assembly hash file. /// private void WriteCachePluginsHash() { @@ -215,38 +204,37 @@ namespace Umbraco.Core.Plugins } /// - /// Returns a unique hash for the combination of FileInfo objects passed in + /// Returns a unique hash for a combination of FileInfo objects. /// /// - /// A collection of files and whether or not to use their file contents to determine the hash or the file's properties + /// A collection of files and whether or not to use their file contents to determine the hash or the file's properties /// (true will make a hash based on it's contents) /// - /// + /// A profiling logger. + /// The hash. internal static long GetFileHash(IEnumerable> filesAndFolders, ProfilingLogger logger) { + var ffA = filesAndFolders.ToArray(); + using (logger.TraceDuration("Determining hash of code files on disk", "Hash determined")) { var hashCombiner = new HashCodeCombiner(); - //get the file info's to check - var fileInfos = filesAndFolders.Where(x => x.Item2 == false).ToArray(); - var fileContents = filesAndFolders.Except(fileInfos); - - //add each unique folder/file to the hash - foreach (var i in fileInfos.Select(x => x.Item1).DistinctBy(x => x.FullName)) - { - hashCombiner.AddFileSystemItem(i); - } + // get the file info's to check + var fileInfos = ffA.Where(x => x.Item2 == false).ToArray(); + var fileContents = ffA.Except(fileInfos); - //add each unique file's contents to the hash - foreach (var i in fileContents.Select(x => x.Item1).DistinctBy(x => x.FullName)) + // add each unique folder/file to the hash + foreach (var i in fileInfos.Select(x => x.Item1).DistinctBy(x => x.FullName)) + hashCombiner.AddFileSystemItem(i); + + // add each unique file's contents to the hash + foreach (var i in fileContents.Select(x => x.Item1) + .DistinctBy(x => x.FullName) + .Where(x => File.Exists(x.FullName))) { - if (File.Exists(i.FullName)) - { - var content = File.ReadAllText(i.FullName).Replace("\r\n", string.Empty).Replace("\n", string.Empty).Replace("\r", string.Empty); - hashCombiner.AddCaseInsensitiveString(content); - } - + var content = File.ReadAllText(i.FullName).Replace("\r\n", string.Empty).Replace("\n", string.Empty).Replace("\r", string.Empty); + hashCombiner.AddCaseInsensitiveString(content); } return ConvertPluginsHashFromHex(hashCombiner.GetCombinedHashCode()); @@ -259,11 +247,10 @@ namespace Umbraco.Core.Plugins { var hashCombiner = new HashCodeCombiner(); - //add each unique folder/file to the hash + // add each unique folder/file to the hash foreach (var i in filesAndFolders.DistinctBy(x => x.FullName)) - { hashCombiner.AddFileSystemItem(i); - } + return ConvertPluginsHashFromHex(hashCombiner.GetCombinedHashCode()); } } @@ -276,16 +263,12 @@ namespace Umbraco.Core.Plugins internal static long ConvertPluginsHashFromHex(string val) { long outVal; - if (Int64.TryParse(val, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out outVal)) - { - return outVal; - } - return 0; + return long.TryParse(val, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out outVal) ? outVal : 0; } /// /// Attempts to resolve the list of plugin + assemblies found in the runtime for the base type 'T' passed in. - /// If the cache file doesn't exist, fails to load, is corrupt or the type 'T' element is not found then + /// If the cache file doesn't exist, fails to load, is corrupt or the type 'T' element is not found then /// a false attempt is returned. /// /// @@ -293,13 +276,13 @@ namespace Umbraco.Core.Plugins internal Attempt> TryGetCachedPluginsFromFile(TypeResolutionKind resolutionType) { var filePath = GetPluginListFilePath(); - if (!File.Exists(filePath)) + if (File.Exists(filePath) == false) return Attempt>.Fail(); try { - //we will load the xml document, if the app context exist, we will load it from the cache (which is only around for 5 minutes) - //while the app boots up, this should save some IO time on app startup when the app context is there (which is always unless in unit tests) + // we will load the xml document, if the app context exist, we will load it from the cache (which is only around for 5 minutes) + // while the app boots up, this should save some IO time on app startup when the app context is there (which is always unless in unit tests) var xml = _runtimeCache.GetCacheItem(CacheKey, () => XDocument.Load(filePath), new TimeSpan(0, 0, 5, 0)); @@ -313,17 +296,17 @@ namespace Umbraco.Core.Plugins && ((string)x.Attribute("type")) == typeof(T).FullName && ((string)x.Attribute("resolutionType")) == resolutionType.ToString()); - //return false but specify this exception type so we can detect it + // return false but specify this exception type so we can detect it if (typeElement == null) return Attempt>.Fail(new CachedPluginNotFoundInFileException()); - //return success + // return success return Attempt.Succeed(typeElement.Elements("add") .Select(x => (string)x.Attribute("type"))); } catch (Exception ex) { - //if the file is corrupted, etc... return false + // if the file is corrupted, etc... return false return Attempt>.Fail(ex); } } @@ -345,15 +328,15 @@ namespace Umbraco.Core.Plugins _runtimeCache.ClearCacheItem(CacheKey); } - + private string GetPluginListFilePath() { - return Path.Combine(_tempFolder, string.Format("umbraco-plugins.{0}.list", NetworkHelper.FileSafeMachineName)); + return Path.Combine(_tempFolder, $"umbraco-plugins.{NetworkHelper.FileSafeMachineName}.list"); } private string GetPluginHashFilePath() { - return Path.Combine(_tempFolder, string.Format("umbraco-plugins.{0}.hash", NetworkHelper.FileSafeMachineName)); + return Path.Combine(_tempFolder, $"umbraco-plugins.{NetworkHelper.FileSafeMachineName}.hash"); } /// @@ -361,30 +344,25 @@ namespace Umbraco.Core.Plugins /// /// /// - /// This method exists purely due to an error in 4.11. We were writing the plugin list file without the + /// This method exists purely due to an error in 4.11. We were writing the plugin list file without the /// type resolution kind which will have caused some problems. Now we detect this legacy file and if it is detected /// we remove it so it can be recreated properly. /// internal bool DetectLegacyPluginListFile() { var filePath = GetPluginListFilePath(); - if (!File.Exists(filePath)) + if (File.Exists(filePath) == false) return false; try { var xml = XDocument.Load(filePath); - if (xml.Root == null) - return false; - var typeElement = xml.Root.Elements() + var typeElement = xml.Root?.Elements() .FirstOrDefault(x => x.Name.LocalName == "baseType"); - if (typeElement == null) - return false; - //now check if the typeElement is missing the resolutionType attribute - return typeElement.Attributes().All(x => x.Name.LocalName != "resolutionType"); + return typeElement != null && typeElement.Attributes().All(x => x.Name.LocalName != "resolutionType"); } catch (Exception) { @@ -422,17 +400,17 @@ namespace Umbraco.Core.Plugins } catch { - //if there's an exception loading then this is somehow corrupt, we'll just replace it. + // if there's an exception loading then this is somehow corrupt, we'll just replace it. File.Delete(filePath); - //create the document and the root + // create the document and the root xml = new XDocument(new XElement("plugins")); } if (xml.Root == null) { - //if for some reason there is no root, create it + // if for some reason there is no root, create it xml.Add(new XElement("plugins")); } - //find the type 'T' element to add or update + // find the type 'T' element to add or update var typeElement = xml.Root.Elements() .SingleOrDefault(x => x.Name.LocalName == "baseType" @@ -441,95 +419,34 @@ namespace Umbraco.Core.Plugins if (typeElement == null) { - //create the type element + // create the type element typeElement = new XElement("baseType", new XAttribute("type", typeof(T).FullName), new XAttribute("resolutionType", resolutionType.ToString())); - //then add it to the root + // then add it to the root xml.Root.Add(typeElement); } - //now we have the type element, we need to clear any previous types as children and add/update it with new ones + // now we have the type element, we need to clear any previous types as children and add/update it with new ones typeElement.ReplaceNodes(typesFound.Select(x => new XElement("add", new XAttribute("type", x.AssemblyQualifiedName)))); - //save the xml file + // save the xml file xml.Save(filePath); } #endregion - private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(); - private readonly HashSet _types = new HashSet(); - private IEnumerable _assemblies; - /// - /// Returns all found property editors (based on the resolved Iparameter editors - this saves a scan) - /// - internal IEnumerable ResolvePropertyEditors() - { - //return all proeprty editor types found except for the base property editor type - return ResolveTypes() - .Where(x => x.IsType()) - .Except(new[] { typeof(PropertyEditor) }); - } - - /// - /// Returns all found parameter editors (which includes property editors) - /// - internal IEnumerable ResolveParameterEditors() - { - //return all paramter editor types found except for the base property editor type - return ResolveTypes() - .Except(new[] { typeof(ParameterEditor), typeof(PropertyEditor) }); - } - - /// - /// Returns all available IApplicationStartupHandler objects - /// - /// - internal IEnumerable ResolveApplicationStartupHandlers() - { - return ResolveTypes(); - } - - /// - /// Returns all classes of type ICacheRefresher - /// - /// - internal IEnumerable ResolveCacheRefreshers() - { - return ResolveTypes(); - } - - /// - /// Returns all available IPackageAction in application - /// - /// - internal IEnumerable ResolvePackageActions() - { - return ResolveTypes(); - } - - - - /// - /// Returns all mapper types that have a MapperFor attribute defined - /// - /// - internal IEnumerable ResolveAssignedMapperTypes() - { - return ResolveTypesWithAttribute(); - } - - /// - /// Gets/sets which assemblies to scan when type finding, generally used for unit testing, if not explicitly set + /// Gets or sets which assemblies to scan when type finding, generally used for unit testing, if not explicitly set /// this will search all assemblies known to have plugins and exclude ones known to not have them. /// internal IEnumerable AssembliesToScan { get { return _assemblies ?? (_assemblies = TypeFinder.GetAssembliesWithKnownExclusions()); } set { _assemblies = value; } - } + } + + #region Resolve Types private IEnumerable ResolveTypes( Func> finder, @@ -542,7 +459,7 @@ namespace Umbraco.Core.Plugins using (_logger.DebugDuration( $"Starting resolution types of {typeof(T).FullName}", - $"Completed resolution of types of {typeof(T).FullName}, found {typesFound.Count}", + $"Completed resolution of types of {typeof(T).FullName}", // cannot contain typesFound.Count as it's evaluated before the find! 50)) { //check if the TypeList already exists, if so return it, if not we'll create it @@ -553,7 +470,7 @@ namespace Umbraco.Core.Plugins { _logger.Logger.Debug("Existing typeList found for {0} with resolution type {1}", () => typeof(T), () => resolutionType); } - + //if we're not caching the result then proceed, or if the type list doesn't exist then proceed if (cacheResult == false || typeList == null) { @@ -571,7 +488,7 @@ namespace Umbraco.Core.Plugins //here we need to identify if the CachedPluginNotFoundInFile was the exception, if it was then we need to re-scan //in some cases the plugin will not have been scanned for on application startup, but the assemblies haven't changed //so in this instance there will never be a result. - if (fileCacheResult.Exception != null && fileCacheResult.Exception is CachedPluginNotFoundInFileException) + if (fileCacheResult.Exception is CachedPluginNotFoundInFileException) { _logger.Logger.Debug("Tried to find typelist for type {0} and resolution {1} in file cache but the type was not found so loading types by assembly scan ", () => typeof(T), () => resolutionType); @@ -595,7 +512,7 @@ namespace Umbraco.Core.Plugins } catch (Exception ex) { - //if there are any exceptions loading types, we have to exist, this should never happen so + //if there are any exceptions loading types, we have to exist, this should never happen so //we will need to revert to scanning for types. successfullyLoadedFromCache = false; _logger.Logger.Error("Could not load a cached plugin type: " + t + " now reverting to re-scanning assemblies for the base type: " + typeof(T).FullName, ex); @@ -640,31 +557,27 @@ namespace Umbraco.Core.Plugins } /// - /// This method invokes the finder which scans the assemblies for the types and then loads the result into the type finder. - /// Once the results are loaded, we update the cached type xml file + /// Invokes the finder which scans the assemblies for the types and then loads the result into the type finder, + /// then updates the cached type xml file. /// /// /// /// - /// - /// THIS METHODS IS NOT THREAD SAFE - /// + /// This method is not thread safe. private void LoadViaScanningAndUpdateCacheFile(TypeList typeList, TypeResolutionKind resolutionKind, Func> finder) { - //we don't have a cache for this so proceed to look them up by scanning + // we don't have a cache for this so proceed to look them up by scanning foreach (var t in finder()) - { typeList.AddType(t); - } + UpdateCachedPluginsFile(typeList.GetTypes(), resolutionKind); } - #region Public Methods /// - /// Generic method to find the specified type and cache the result + /// Resolves specified types. /// - /// - /// + /// The type to find. + /// The types. public IEnumerable ResolveTypes(bool cacheResult = true, IEnumerable specificAssemblies = null) { return ResolveTypes( @@ -674,11 +587,11 @@ namespace Umbraco.Core.Plugins } /// - /// Generic method to find the specified type that has an attribute and cache the result + /// Resolves specified, attributed types. /// - /// - /// - /// + /// The type to find. + /// The type of the attribute. + /// The corresponding types. public IEnumerable ResolveTypesWithAttribute(bool cacheResult = true, IEnumerable specificAssemblies = null) where TAttribute : Attribute { @@ -689,10 +602,10 @@ namespace Umbraco.Core.Plugins } /// - /// Generic method to find any type that has the specified attribute + /// Resolves attributed types. /// - /// - /// + /// The type of the attribute. + /// The corresopnding types. public IEnumerable ResolveAttributedTypes(bool cacheResult = true, IEnumerable specificAssemblies = null) where TAttribute : Attribute { @@ -700,22 +613,22 @@ namespace Umbraco.Core.Plugins () => TypeFinder.FindClassesWithAttribute(specificAssemblies ?? AssembliesToScan), TypeResolutionKind.FindAttributedTypes, cacheResult); - } + } + #endregion + #region Private + /// - /// Used for unit tests + /// Gets the list of types. /// - /// + /// The list of types. + /// For unit tests only. internal HashSet GetTypeLists() { return _types; } - - - #region Private classes/Enums - /// /// The type of resolution being invoked /// @@ -746,7 +659,7 @@ namespace Umbraco.Core.Plugins public override void AddType(Type t) { - //if the type is an attribute type we won't do the type check because typeof is going to be the + //if the type is an attribute type we won't do the type check because typeof is going to be the //attribute type whereas the 't' type is the object type found with the attribute. if (_resolutionType == TypeResolutionKind.FindAttributedTypes || t.IsType()) { @@ -772,14 +685,68 @@ namespace Umbraco.Core.Plugins } /// - /// This class is used simply to determine that a plugin was not found in the cache plugin list with the specified + /// Represents the error that occurs when a plugin was not found in the cache plugin list with the specified /// TypeResolutionKind. /// internal class CachedPluginNotFoundInFileException : Exception - { - - } + { } #endregion } + + internal static class PluginManagerExtensions + { + /// + /// Resolves property editors (based on the resolved Iparameter editors - this saves a scan). + /// + public static IEnumerable ResolvePropertyEditors(this PluginManager mgr) + { + //return all proeprty editor types found except for the base property editor type + return mgr.ResolveTypes() + .Where(x => x.IsType()) + .Except(new[] { typeof(PropertyEditor) }); + } + + /// + /// Resolves parameter editors (which includes property editors) + /// + internal static IEnumerable ResolveParameterEditors(this PluginManager mgr) + { + //return all paramter editor types found except for the base property editor type + return mgr.ResolveTypes() + .Except(new[] { typeof(ParameterEditor), typeof(PropertyEditor) }); + } + + /// + /// Resolves IApplicationStartupHandler objects. + /// + internal static IEnumerable ResolveApplicationStartupHandlers(this PluginManager mgr) + { + return mgr.ResolveTypes(); + } + + /// + /// Resolves ICacheRefresher objects. + /// + internal static IEnumerable ResolveCacheRefreshers(this PluginManager mgr) + { + return mgr.ResolveTypes(); + } + + /// + /// Resolves IPackageAction objects. + /// + internal static IEnumerable ResolvePackageActions(this PluginManager mgr) + { + return mgr.ResolveTypes(); + } + + /// + /// Resolves mapper types that have a MapperFor attribute defined. + /// + internal static IEnumerable ResolveAssignedMapperTypes(this PluginManager mgr) + { + return mgr.ResolveTypesWithAttribute(); + } + } } diff --git a/src/Umbraco.Tests/Plugins/PluginManagerTests.cs b/src/Umbraco.Tests/Plugins/PluginManagerTests.cs index ec49b2b49a..f591d28639 100644 --- a/src/Umbraco.Tests/Plugins/PluginManagerTests.cs +++ b/src/Umbraco.Tests/Plugins/PluginManagerTests.cs @@ -33,7 +33,7 @@ namespace Umbraco.Tests.Plugins public void Initialize() { //this ensures its reset - _manager = new PluginManager(new ActivatorServiceProvider(), new NullCacheProvider(), + _manager = new PluginManager(new NullCacheProvider(), new ProfilingLogger(Mock.Of(), Mock.Of())); //for testing, we'll specify which assemblies are scanned for the PluginTypeResolver diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs index 200db76d04..f8cd3023a6 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs @@ -37,7 +37,7 @@ namespace Umbraco.Tests.PublishedContent // this is so the model factory looks into the test assembly _pluginManager = PluginManager.Current; - PluginManager.Current = new PluginManager(new ActivatorServiceProvider(), new NullCacheProvider(), ProfilingLogger, false) + PluginManager.Current = new PluginManager(new NullCacheProvider(), ProfilingLogger, false) { AssembliesToScan = _pluginManager.AssembliesToScan .Union(new[] { typeof (PublishedContentMoreTests).Assembly}) diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index 37814c3b6d..0c005753cc 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -29,7 +29,7 @@ namespace Umbraco.Tests.PublishedContent // this is so the model factory looks into the test assembly _pluginManager = PluginManager.Current; - PluginManager.Current = new PluginManager(new ActivatorServiceProvider(), CacheHelper.RuntimeCache, ProfilingLogger, false) + PluginManager.Current = new PluginManager(CacheHelper.RuntimeCache, ProfilingLogger, false) { AssembliesToScan = _pluginManager.AssembliesToScan .Union(new[] { typeof(PublishedContentTests).Assembly }) diff --git a/src/Umbraco.Tests/Resolvers/PackageActionsResolverTests.cs b/src/Umbraco.Tests/Resolvers/PackageActionsResolverTests.cs index ccb02a4694..d6fab52f15 100644 --- a/src/Umbraco.Tests/Resolvers/PackageActionsResolverTests.cs +++ b/src/Umbraco.Tests/Resolvers/PackageActionsResolverTests.cs @@ -3,8 +3,8 @@ using System.Linq; using System.Xml; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Plugins; using Umbraco.Core.ObjectResolution; -using Umbraco.Tests.TestHelpers; using Umbraco.Core._Legacy.PackageActions; namespace Umbraco.Tests.Resolvers diff --git a/src/Umbraco.Tests/Resolvers/ResolverBaseTest.cs b/src/Umbraco.Tests/Resolvers/ResolverBaseTest.cs index cdf24667e8..a03d5ff878 100644 --- a/src/Umbraco.Tests/Resolvers/ResolverBaseTest.cs +++ b/src/Umbraco.Tests/Resolvers/ResolverBaseTest.cs @@ -24,7 +24,7 @@ namespace Umbraco.Tests.Resolvers ProfilingLogger = new ProfilingLogger(Mock.Of(), Mock.Of()); - PluginManager = new PluginManager(new ActivatorServiceProvider(), new NullCacheProvider(), + PluginManager = new PluginManager(new NullCacheProvider(), ProfilingLogger, false) { diff --git a/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs b/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs index cd7f0e1a80..7575932112 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs @@ -248,7 +248,6 @@ namespace Umbraco.Tests.TestHelpers if (PluginManager.Current == null || PluginManagerResetRequired) { PluginManager.Current = new PluginManager( - new ActivatorServiceProvider(), CacheHelper.RuntimeCache, ProfilingLogger, false) { AssembliesToScan = new[] diff --git a/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs index 672c682908..8a9617c919 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs @@ -45,7 +45,7 @@ namespace Umbraco.Tests.TestHelpers var logger = new ProfilingLogger(Mock.Of(), Mock.Of()); - PluginManager.Current = new PluginManager(new ActivatorServiceProvider(), new NullCacheProvider(), + PluginManager.Current = new PluginManager(new NullCacheProvider(), logger, false);