Merge branch 'dev-v7.6' of https://github.com/umbraco/Umbraco-CMS into dev-v7.6
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using umbraco.interfaces;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Core.Deploy
|
||||
@@ -8,7 +9,7 @@ namespace Umbraco.Core.Deploy
|
||||
/// <summary>
|
||||
/// Connects to an Umbraco service.
|
||||
/// </summary>
|
||||
public interface IServiceConnector
|
||||
public interface IServiceConnector : IDiscoverable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets an artifact.
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Media
|
||||
{
|
||||
public interface IImageUrlProvider
|
||||
// note: because this interface is obsolete is is *not* IDiscoverable, and in case the
|
||||
// PluginManager is asked to find types implementing this interface it will fall back
|
||||
// to a complete scan.
|
||||
|
||||
[Obsolete("IImageUrlProvider is no longer used and will be removed in future versions")]
|
||||
public interface IImageUrlProvider // IDiscoverable
|
||||
{
|
||||
string Name { get; }
|
||||
string GetImageUrlFromMedia(int mediaId, IDictionary<string, string> parameters);
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
namespace Umbraco.Core.Media
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Media
|
||||
{
|
||||
public interface IThumbnailProvider
|
||||
// note: because this interface is obsolete is is *not* IDiscoverable, and in case the
|
||||
// PluginManager is asked to find types implementing this interface it will fall back
|
||||
// to a complete scan.
|
||||
|
||||
[Obsolete("Thumbnails are generated by ImageProcessor, use that instead")]
|
||||
public interface IThumbnailProvider // : IDiscoverable
|
||||
{
|
||||
bool CanProvideThumbnail(string fileUrl);
|
||||
string GetThumbnailUrl(string fileUrl);
|
||||
|
||||
@@ -63,49 +63,6 @@ namespace Umbraco.Core.ObjectResolution
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE - the ugly code below exists only because of umbraco.BusinessLogic.Actions.Action.ReRegisterActionsAndHandlers
|
||||
// which wants to re-register actions and handlers instead of properly restarting the application. Don't even think
|
||||
// about using it for anything else. Also, while the backdoor is open, the resolution system is locked so nothing
|
||||
// can work properly => deadlocks. Therefore, open the backdoor, do resolution changes EXCLUSIVELY, and close the door!
|
||||
|
||||
/// <summary>
|
||||
/// Returns a disposable object that reprents dirty access to temporarily unfrozen resolution configuration.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Should not be used.</para>
|
||||
/// <para>Should be used in a <c>using(Resolution.DirtyBackdoorToConfiguration) { ... }</c> mode.</para>
|
||||
/// <para>Because we just lift the frozen state, and we don't actually re-freeze, the <c>Frozen</c> event does not trigger.</para>
|
||||
/// </remarks>
|
||||
internal static IDisposable DirtyBackdoorToConfiguration
|
||||
{
|
||||
get { return new DirtyBackdoor(); }
|
||||
}
|
||||
|
||||
// keep the class here because it needs write-access to Resolution.IsFrozen
|
||||
private class DirtyBackdoor : IDisposable
|
||||
{
|
||||
|
||||
private readonly IDisposable _lock;
|
||||
private readonly bool _frozen;
|
||||
|
||||
public DirtyBackdoor()
|
||||
{
|
||||
LogHelper.Debug(typeof(DirtyBackdoor), "Creating back door for resolution");
|
||||
|
||||
_lock = new WriteLock(ConfigurationLock);
|
||||
_frozen = _isFrozen;
|
||||
_isFrozen = false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
LogHelper.Debug(typeof(DirtyBackdoor), "Disposing back door for resolution");
|
||||
|
||||
_isFrozen = _frozen;
|
||||
_lock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Freezes resolution.
|
||||
/// </summary>
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using umbraco.interfaces;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Mappers
|
||||
{
|
||||
public abstract class BaseMapper
|
||||
public abstract class BaseMapper : IDiscoverable
|
||||
{
|
||||
private readonly ISqlSyntaxProvider _sqlSyntax;
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
namespace Umbraco.Core.Persistence.Migrations
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations
|
||||
{
|
||||
/// <summary>
|
||||
/// Marker interface for database migrations
|
||||
/// </summary>
|
||||
public interface IMigration
|
||||
public interface IMigration : IDiscoverable
|
||||
{
|
||||
void Up();
|
||||
void Down();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
public interface IParameterEditor
|
||||
public interface IParameterEditor : IDiscoverable
|
||||
{
|
||||
/// <summary>
|
||||
/// The id of the property editor
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
@@ -7,8 +8,8 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// </summary>
|
||||
// todo: drop IPropertyEditorValueConverter support (when?).
|
||||
[Obsolete("Use IPropertyValueConverter.")]
|
||||
public interface IPropertyEditorValueConverter
|
||||
{
|
||||
public interface IPropertyEditorValueConverter : IDiscoverable
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether this provider applies to the specified property.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using umbraco.interfaces;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides published content properties conversion service.
|
||||
/// </summary>
|
||||
public interface IPropertyValueConverter
|
||||
public interface IPropertyValueConverter : IDiscoverable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the converter supports a property type.
|
||||
|
||||
@@ -1,32 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using System.Web.Compilation;
|
||||
using System.Web.Hosting;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// A utility class to find all classes of a certain type by reflection in the current bin folder
|
||||
/// of the web application.
|
||||
/// </summary>
|
||||
public static class TypeFinder
|
||||
{
|
||||
private static volatile HashSet<Assembly> _localFilteredAssemblyCache = null;
|
||||
private static volatile HashSet<Assembly> _localFilteredAssemblyCache;
|
||||
private static readonly object LocalFilteredAssemblyCacheLocker = new object();
|
||||
|
||||
/// <summary>
|
||||
@@ -63,7 +55,7 @@ namespace Umbraco.Core
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
if (!(e.InnerException is SecurityException))
|
||||
if ((e.InnerException is SecurityException) == false)
|
||||
throw;
|
||||
}
|
||||
|
||||
@@ -99,7 +91,7 @@ namespace Umbraco.Core
|
||||
}
|
||||
|
||||
//if for some reason they are still no assemblies, then use the AppDomain to load in already loaded assemblies.
|
||||
if (!assemblies.Any())
|
||||
if (assemblies.Any() == false)
|
||||
{
|
||||
foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
@@ -111,12 +103,12 @@ namespace Umbraco.Core
|
||||
var fileExtensions = new[] { ".cs", ".vb" }; //only vb and cs files are supported
|
||||
var appCodeFolder = new DirectoryInfo(IOHelper.MapPath(IOHelper.ResolveUrl("~/App_code")));
|
||||
//check if the folder exists and if there are any files in it with the supported file extensions
|
||||
if (appCodeFolder.Exists && (fileExtensions.Any(x => appCodeFolder.GetFiles("*" + x).Any())))
|
||||
if (appCodeFolder.Exists && fileExtensions.Any(x => appCodeFolder.GetFiles("*" + x).Any()))
|
||||
{
|
||||
try
|
||||
{
|
||||
var appCodeAssembly = Assembly.Load("App_Code");
|
||||
if (!assemblies.Contains(appCodeAssembly)) // BuildManager will find App_Code already
|
||||
if (assemblies.Contains(appCodeAssembly) == false) // BuildManager will find App_Code already
|
||||
assemblies.Add(appCodeAssembly);
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
@@ -128,7 +120,7 @@ namespace Umbraco.Core
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
if (!(e.InnerException is SecurityException))
|
||||
if (e.InnerException is SecurityException == false)
|
||||
throw;
|
||||
}
|
||||
|
||||
@@ -145,23 +137,15 @@ namespace Umbraco.Core
|
||||
internal static HashSet<Assembly> GetAssembliesWithKnownExclusions(
|
||||
IEnumerable<Assembly> excludeFromResults = null)
|
||||
{
|
||||
if (_localFilteredAssemblyCache == null)
|
||||
lock (LocalFilteredAssemblyCacheLocker)
|
||||
{
|
||||
lock (LocalFilteredAssemblyCacheLocker)
|
||||
{
|
||||
//double check
|
||||
if (_localFilteredAssemblyCache == null)
|
||||
{
|
||||
_localFilteredAssemblyCache = new HashSet<Assembly>();
|
||||
var assemblies = GetFilteredAssemblies(excludeFromResults, KnownAssemblyExclusionFilter);
|
||||
foreach (var a in assemblies)
|
||||
{
|
||||
_localFilteredAssemblyCache.Add(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_localFilteredAssemblyCache != null)
|
||||
return _localFilteredAssemblyCache;
|
||||
|
||||
var assemblies = GetFilteredAssemblies(excludeFromResults, KnownAssemblyExclusionFilter);
|
||||
_localFilteredAssemblyCache = new HashSet<Assembly>(assemblies);
|
||||
return _localFilteredAssemblyCache;
|
||||
}
|
||||
return _localFilteredAssemblyCache;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -180,9 +164,9 @@ namespace Umbraco.Core
|
||||
exclusionFilter = new string[] { };
|
||||
|
||||
return GetAllAssemblies()
|
||||
.Where(x => !excludeFromResults.Contains(x)
|
||||
&& !x.GlobalAssemblyCache
|
||||
&& !exclusionFilter.Any(f => x.FullName.StartsWith(f)));
|
||||
.Where(x => excludeFromResults.Contains(x) == false
|
||||
&& x.GlobalAssemblyCache == false
|
||||
&& exclusionFilter.Any(f => x.FullName.StartsWith(f)) == false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -298,7 +282,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException("assemblies");
|
||||
|
||||
return GetClasses(assignTypeFrom, assemblies, onlyConcreteClasses,
|
||||
return GetClassesWithBaseType(assignTypeFrom, assemblies, onlyConcreteClasses,
|
||||
//the additional filter will ensure that any found types also have the attribute applied.
|
||||
t => t.GetCustomAttributes<TAttribute>(false).Any());
|
||||
}
|
||||
@@ -324,7 +308,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException("assemblies");
|
||||
|
||||
return GetClasses(typeof(T), assemblies, onlyConcreteClasses);
|
||||
return GetClassesWithBaseType(typeof(T), assemblies, onlyConcreteClasses);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -363,105 +347,9 @@ namespace Umbraco.Core
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses)
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException("assemblies");
|
||||
|
||||
if (TypeHelper.IsTypeAssignableFrom<Attribute>(attributeType) == false)
|
||||
throw new ArgumentException("The type specified: " + attributeType + " is not an Attribute type");
|
||||
|
||||
var foundAttributedTypes = new HashSet<Type>();
|
||||
|
||||
var assemblyList = assemblies.ToArray();
|
||||
|
||||
//find all assembly references that are referencing the attribute type's assembly since we
|
||||
//should only be scanning those assemblies because any other assembly will definitely not
|
||||
//contain a class that has this attribute.
|
||||
var referencedAssemblies = TypeHelper.GetReferencedAssemblies(attributeType, assemblyList);
|
||||
|
||||
//get a list of non-referenced assemblies (we'll use this when we recurse below)
|
||||
var otherAssemblies = assemblyList.Where(x => referencedAssemblies.Contains(x) == false).ToArray();
|
||||
|
||||
//loop through the referenced assemblies
|
||||
foreach (var a in referencedAssemblies)
|
||||
{
|
||||
//get all types in this assembly
|
||||
var allTypes = GetTypesWithFormattedException(a)
|
||||
.ToArray();
|
||||
|
||||
var attributedTypes = new Type[] { };
|
||||
try
|
||||
{
|
||||
//now filter the types based on the onlyConcreteClasses flag, not interfaces, not static classes but have
|
||||
//the specified attribute
|
||||
attributedTypes = allTypes
|
||||
.Where(t => (TypeHelper.IsNonStaticClass(t)
|
||||
&& (onlyConcreteClasses == false || t.IsAbstract == false))
|
||||
//the type must have this attribute
|
||||
&& t.GetCustomAttributes(attributeType, false).Any())
|
||||
.ToArray();
|
||||
}
|
||||
catch (TypeLoadException ex)
|
||||
{
|
||||
LogHelper.Error(typeof(TypeFinder), string.Format("Could not query types on {0} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", a), ex);
|
||||
continue;
|
||||
}
|
||||
|
||||
//add the types to our list to return
|
||||
foreach (var t in attributedTypes)
|
||||
{
|
||||
foundAttributedTypes.Add(t);
|
||||
}
|
||||
|
||||
//get all attributes of the type being searched for
|
||||
var allAttributeTypes = allTypes.Where(attributeType.IsAssignableFrom);
|
||||
|
||||
//now we need to include types that may be inheriting from sub classes of the attribute type being searched for
|
||||
//so we will search in assemblies that reference those types too.
|
||||
foreach (var subTypesInAssembly in allAttributeTypes.GroupBy(x => x.Assembly))
|
||||
{
|
||||
|
||||
//So that we are not scanning too much, we need to group the sub types:
|
||||
// * if there is more than 1 sub type in the same assembly then we should only search on the 'lowest base' type.
|
||||
// * We should also not search for sub types if the type is sealed since you cannot inherit from a sealed class
|
||||
// * We should not search for sub types if the type is static since you cannot inherit from them.
|
||||
var subTypeList = subTypesInAssembly
|
||||
.Where(t => t.IsSealed == false && TypeHelper.IsStaticClass(t) == false)
|
||||
.ToArray();
|
||||
|
||||
var baseClassAttempt = TypeHelper.GetLowestBaseType(subTypeList);
|
||||
|
||||
//if there's a base class amongst the types then we'll only search for that type.
|
||||
//otherwise we'll have to search for all of them.
|
||||
var subTypesToSearch = new HashSet<Type>();
|
||||
if (baseClassAttempt.Success)
|
||||
{
|
||||
subTypesToSearch.Add(baseClassAttempt.Result);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var t in subTypeList)
|
||||
{
|
||||
subTypesToSearch.Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var typeToSearch in subTypesToSearch)
|
||||
{
|
||||
//recursively find the types inheriting from this sub type in the other non-scanned assemblies.
|
||||
var foundTypes = FindClassesWithAttribute(typeToSearch, otherAssemblies, onlyConcreteClasses);
|
||||
|
||||
foreach (var f in foundTypes)
|
||||
{
|
||||
foundAttributedTypes.Add(f);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return foundAttributedTypes;
|
||||
return GetClassesWithAttribute(attributeType, assemblies, onlyConcreteClasses);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute.
|
||||
/// </summary>
|
||||
@@ -485,122 +373,129 @@ namespace Umbraco.Core
|
||||
return FindClassesWithAttribute<T>(GetAssembliesWithKnownExclusions());
|
||||
}
|
||||
|
||||
|
||||
#region Private methods
|
||||
|
||||
private static IEnumerable<Type> GetClassesWithAttribute(
|
||||
Type attributeType,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses)
|
||||
{
|
||||
if (typeof(Attribute).IsAssignableFrom(attributeType) == false)
|
||||
throw new ArgumentException("Type " + attributeType + " is not an Attribute type.");
|
||||
|
||||
var candidateAssemblies = new HashSet<Assembly>(assemblies);
|
||||
var attributeAssemblyIsCandidate = candidateAssemblies.Contains(attributeType.Assembly);
|
||||
candidateAssemblies.Remove(attributeType.Assembly);
|
||||
var types = new List<Type>();
|
||||
|
||||
var stack = new Stack<Assembly>();
|
||||
stack.Push(attributeType.Assembly);
|
||||
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
var assembly = stack.Pop();
|
||||
|
||||
Type[] assemblyTypes = null;
|
||||
if (assembly != attributeType.Assembly || attributeAssemblyIsCandidate)
|
||||
{
|
||||
// get all assembly types that can be assigned to baseType
|
||||
try
|
||||
{
|
||||
assemblyTypes = GetTypesWithFormattedException(assembly)
|
||||
.ToArray(); // in try block
|
||||
}
|
||||
catch (TypeLoadException ex)
|
||||
{
|
||||
LogHelper.Error(typeof(TypeFinder), string.Format("Could not query types on {0} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", assembly), ex);
|
||||
continue;
|
||||
}
|
||||
|
||||
types.AddRange(assemblyTypes.Where(x =>
|
||||
x.IsClass // only classes
|
||||
&& (x.IsAbstract == false || x.IsSealed == false) // ie non-static, static is abstract and sealed
|
||||
&& x.IsNestedPrivate == false // exclude nested private
|
||||
&& (onlyConcreteClasses == false || x.IsAbstract == false) // exclude abstract
|
||||
&& x.GetCustomAttribute<HideFromTypeFinderAttribute>() == null // exclude hidden
|
||||
&& x.GetCustomAttributes(attributeType, false).Any())); // marked with the attribute
|
||||
}
|
||||
|
||||
if (assembly != attributeType.Assembly && assemblyTypes.Where(attributeType.IsAssignableFrom).Any() == false)
|
||||
continue;
|
||||
|
||||
foreach (var referencing in TypeHelper.GetReferencingAssemblies(assembly, candidateAssemblies))
|
||||
{
|
||||
candidateAssemblies.Remove(referencing);
|
||||
stack.Push(referencing);
|
||||
}
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds types that are assignable from the assignTypeFrom parameter and will scan for these types in the assembly
|
||||
/// list passed in, however we will only scan assemblies that have a reference to the assignTypeFrom Type or any type
|
||||
/// deriving from the base type.
|
||||
/// </summary>
|
||||
/// <param name="assignTypeFrom"></param>
|
||||
/// <param name="baseType"></param>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <param name="additionalFilter">An additional filter to apply for what types will actually be included in the return value</param>
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<Type> GetClasses(
|
||||
Type assignTypeFrom,
|
||||
private static IEnumerable<Type> GetClassesWithBaseType(
|
||||
Type baseType,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses,
|
||||
Func<Type, bool> additionalFilter = null)
|
||||
{
|
||||
//the default filter will always return true.
|
||||
if (additionalFilter == null)
|
||||
var candidateAssemblies = new HashSet<Assembly>(assemblies);
|
||||
var baseTypeAssemblyIsCandidate = candidateAssemblies.Contains(baseType.Assembly);
|
||||
candidateAssemblies.Remove(baseType.Assembly);
|
||||
var types = new List<Type>();
|
||||
|
||||
var stack = new Stack<Assembly>();
|
||||
stack.Push(baseType.Assembly);
|
||||
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
additionalFilter = type => true;
|
||||
}
|
||||
var assembly = stack.Pop();
|
||||
|
||||
var foundAssignableTypes = new HashSet<Type>();
|
||||
|
||||
var assemblyList = assemblies.ToArray();
|
||||
|
||||
//find all assembly references that are referencing the current type's assembly since we
|
||||
//should only be scanning those assemblies because any other assembly will definitely not
|
||||
//contain sub type's of the one we're currently looking for
|
||||
var referencedAssemblies = TypeHelper.GetReferencedAssemblies(assignTypeFrom, assemblyList);
|
||||
|
||||
//get a list of non-referenced assemblies (we'll use this when we recurse below)
|
||||
var otherAssemblies = assemblyList.Where(x => referencedAssemblies.Contains(x) == false).ToArray();
|
||||
|
||||
//loop through the referenced assemblies
|
||||
foreach (var a in referencedAssemblies)
|
||||
{
|
||||
//get all types in the assembly that are sub types of the current type
|
||||
var allSubTypes = GetTypesWithFormattedException(a)
|
||||
.Where(assignTypeFrom.IsAssignableFrom)
|
||||
.ToArray();
|
||||
|
||||
var filteredTypes = new Type[] { };
|
||||
try
|
||||
// get all assembly types that can be assigned to baseType
|
||||
Type[] assemblyTypes = null;
|
||||
if (assembly != baseType.Assembly || baseTypeAssemblyIsCandidate)
|
||||
{
|
||||
//now filter the types based on the onlyConcreteClasses flag, not interfaces, not static classes
|
||||
filteredTypes = allSubTypes
|
||||
.Where(t => (TypeHelper.IsNonStaticClass(t)
|
||||
//Do not include nested private classes - since we are in full trust now this will find those too!
|
||||
&& t.IsNestedPrivate == false
|
||||
&& (onlyConcreteClasses == false || t.IsAbstract == false)
|
||||
//Do not include classes that are flagged to hide from the type finder
|
||||
&& t.GetCustomAttribute<HideFromTypeFinderAttribute>() == null
|
||||
&& additionalFilter(t)))
|
||||
.ToArray();
|
||||
try
|
||||
{
|
||||
assemblyTypes = GetTypesWithFormattedException(assembly)
|
||||
.Where(baseType.IsAssignableFrom)
|
||||
.ToArray(); // in try block
|
||||
}
|
||||
catch (TypeLoadException ex)
|
||||
{
|
||||
LogHelper.Error(typeof(TypeFinder), string.Format("Could not query types on {0} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", assembly), ex);
|
||||
continue;
|
||||
}
|
||||
|
||||
types.AddRange(assemblyTypes.Where(x =>
|
||||
x.IsClass // only classes
|
||||
&& (x.IsAbstract == false || x.IsSealed == false) // ie non-static, static is abstract and sealed
|
||||
&& x.IsNestedPrivate == false // exclude nested private
|
||||
&& (onlyConcreteClasses == false || x.IsAbstract == false) // exclude abstract
|
||||
&& x.GetCustomAttribute<HideFromTypeFinderAttribute>() == null // exclude hidden
|
||||
&& (additionalFilter == null || additionalFilter(x)))); // filter
|
||||
}
|
||||
catch (TypeLoadException ex)
|
||||
{
|
||||
LogHelper.Error(typeof(TypeFinder), string.Format("Could not query types on {0} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", a), ex);
|
||||
|
||||
if (assembly != baseType.Assembly && assemblyTypes.All(x => x.IsSealed))
|
||||
continue;
|
||||
}
|
||||
|
||||
//add the types to our list to return
|
||||
foreach (var t in filteredTypes)
|
||||
foreach (var referencing in TypeHelper.GetReferencingAssemblies(assembly, candidateAssemblies))
|
||||
{
|
||||
foundAssignableTypes.Add(t);
|
||||
candidateAssemblies.Remove(referencing);
|
||||
stack.Push(referencing);
|
||||
}
|
||||
|
||||
//now we need to include types that may be inheriting from sub classes of the type being searched for
|
||||
//so we will search in assemblies that reference those types too.
|
||||
foreach (var subTypesInAssembly in allSubTypes.GroupBy(x => x.Assembly))
|
||||
{
|
||||
|
||||
//So that we are not scanning too much, we need to group the sub types:
|
||||
// * if there is more than 1 sub type in the same assembly then we should only search on the 'lowest base' type.
|
||||
// * We should also not search for sub types if the type is sealed since you cannot inherit from a sealed class
|
||||
// * We should not search for sub types if the type is static since you cannot inherit from them.
|
||||
var subTypeList = subTypesInAssembly
|
||||
.Where(t => t.IsSealed == false && TypeHelper.IsStaticClass(t) == false)
|
||||
.ToArray();
|
||||
|
||||
var baseClassAttempt = TypeHelper.GetLowestBaseType(subTypeList);
|
||||
|
||||
//if there's a base class amongst the types then we'll only search for that type.
|
||||
//otherwise we'll have to search for all of them.
|
||||
var subTypesToSearch = new HashSet<Type>();
|
||||
if (baseClassAttempt.Success)
|
||||
{
|
||||
subTypesToSearch.Add(baseClassAttempt.Result);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var t in subTypeList)
|
||||
{
|
||||
subTypesToSearch.Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var typeToSearch in subTypesToSearch)
|
||||
{
|
||||
//recursively find the types inheriting from this sub type in the other non-scanned assemblies.
|
||||
var foundTypes = GetClasses(typeToSearch, otherAssemblies, onlyConcreteClasses, additionalFilter);
|
||||
|
||||
foreach (var f in foundTypes)
|
||||
{
|
||||
foundAssignableTypes.Add(f);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return foundAssignableTypes;
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
internal static IEnumerable<Type> GetTypesWithFormattedException(Assembly a)
|
||||
@@ -666,7 +561,6 @@ namespace Umbraco.Core
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public static Type GetTypeByName(string typeName)
|
||||
{
|
||||
var type = BuildManager.GetType(typeName, false);
|
||||
@@ -684,6 +578,5 @@ namespace Umbraco.Core
|
||||
.Select(x => x.GetType(typeName))
|
||||
.FirstOrDefault(x => x != null);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,12 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
internal static class TypeHelper
|
||||
{
|
||||
|
||||
private static readonly ConcurrentDictionary<Type, FieldInfo[]> GetFieldsCache = new ConcurrentDictionary<Type, FieldInfo[]>();
|
||||
private static readonly ConcurrentDictionary<Tuple<Type, bool, bool, bool>, PropertyInfo[]> GetPropertiesCache = new ConcurrentDictionary<Tuple<Type, bool, bool, bool>, PropertyInfo[]>();
|
||||
private static readonly ConcurrentDictionary<Tuple<Type, bool, bool, bool>, PropertyInfo[]> GetPropertiesCache
|
||||
= new ConcurrentDictionary<Tuple<Type, bool, bool, bool>, PropertyInfo[]>();
|
||||
private static readonly ConcurrentDictionary<Type, FieldInfo[]> GetFieldsCache
|
||||
= new ConcurrentDictionary<Type, FieldInfo[]>();
|
||||
|
||||
private static readonly Assembly[] EmptyAssemblies = new Assembly[0];
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the method is actually overriding a base method
|
||||
@@ -30,44 +33,40 @@ namespace Umbraco.Core
|
||||
/// <summary>
|
||||
/// Find all assembly references that are referencing the assignTypeFrom Type's assembly found in the assemblyList
|
||||
/// </summary>
|
||||
/// <param name="assignTypeFrom"></param>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="assembly">The referenced assembly.</param>
|
||||
/// <param name="assemblies">A list of assemblies.</param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// If the assembly of the assignTypeFrom Type is in the App_Code assembly, then we return nothing since things cannot
|
||||
/// reference that assembly, same with the global.asax assembly.
|
||||
/// </remarks>
|
||||
public static Assembly[] GetReferencedAssemblies(Type assignTypeFrom, IEnumerable<Assembly> assemblies)
|
||||
public static Assembly[] GetReferencingAssemblies(Assembly assembly, IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
//check if it is the app_code assembly.
|
||||
//check if it is App_global.asax assembly
|
||||
if (assignTypeFrom.Assembly.IsAppCodeAssembly() || assignTypeFrom.Assembly.IsGlobalAsaxAssembly())
|
||||
{
|
||||
return Enumerable.Empty<Assembly>().ToArray();
|
||||
}
|
||||
if (assembly.IsAppCodeAssembly() || assembly.IsGlobalAsaxAssembly())
|
||||
return EmptyAssemblies;
|
||||
|
||||
|
||||
//find all assembly references that are referencing the current type's assembly since we
|
||||
//should only be scanning those assemblies because any other assembly will definitely not
|
||||
//contain sub type's of the one we're currently looking for
|
||||
return assemblies
|
||||
.Where(assembly =>
|
||||
assembly == assignTypeFrom.Assembly
|
||||
|| HasReferenceToAssemblyWithName(assembly, assignTypeFrom.Assembly.GetName().Name))
|
||||
.ToArray();
|
||||
// find all assembly references that are referencing the current type's assembly since we
|
||||
// should only be scanning those assemblies because any other assembly will definitely not
|
||||
// contain sub type's of the one we're currently looking for
|
||||
var name = assembly.GetName().Name;
|
||||
return assemblies.Where(x => x == assembly || HasReference(x, name)).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// checks if the assembly has a reference with the same name as the expected assembly name.
|
||||
/// Determines if an assembly references another assembly.
|
||||
/// </summary>
|
||||
/// <param name="assembly"></param>
|
||||
/// <param name="expectedAssemblyName"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
private static bool HasReferenceToAssemblyWithName(Assembly assembly, string expectedAssemblyName)
|
||||
{
|
||||
return assembly
|
||||
.GetReferencedAssemblies()
|
||||
.Select(a => a.Name)
|
||||
.Contains(expectedAssemblyName, StringComparer.Ordinal);
|
||||
public static bool HasReference(Assembly assembly, string name)
|
||||
{
|
||||
// ReSharper disable once LoopCanBeConvertedToQuery - no!
|
||||
foreach (var a in assembly.GetReferencedAssemblies())
|
||||
{
|
||||
if (string.Equals(a.Name, name, StringComparison.Ordinal)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -106,13 +105,10 @@ namespace Umbraco.Core
|
||||
public static Attempt<Type> GetLowestBaseType(params Type[] types)
|
||||
{
|
||||
if (types.Length == 0)
|
||||
{
|
||||
return Attempt<Type>.Fail();
|
||||
}
|
||||
if (types.Length == 1)
|
||||
{
|
||||
|
||||
if (types.Length == 1)
|
||||
return Attempt.Succeed(types[0]);
|
||||
}
|
||||
|
||||
foreach (var curr in types)
|
||||
{
|
||||
@@ -196,20 +192,15 @@ namespace Umbraco.Core
|
||||
/// <param name="includeIndexed"></param>
|
||||
/// <param name="caseSensitive"> </param>
|
||||
/// <returns></returns>
|
||||
public static PropertyInfo GetProperty(Type type, string name,
|
||||
bool mustRead = true,
|
||||
bool mustWrite = true,
|
||||
public static PropertyInfo GetProperty(Type type, string name,
|
||||
bool mustRead = true,
|
||||
bool mustWrite = true,
|
||||
bool includeIndexed = false,
|
||||
bool caseSensitive = true)
|
||||
{
|
||||
return CachedDiscoverableProperties(type, mustRead, mustWrite, includeIndexed)
|
||||
.FirstOrDefault(x =>
|
||||
{
|
||||
if (caseSensitive)
|
||||
return x.Name == name;
|
||||
return x.Name.InvariantEquals(name);
|
||||
});
|
||||
}
|
||||
return CachedDiscoverableProperties(type, mustRead, mustWrite, includeIndexed)
|
||||
.FirstOrDefault(x => caseSensitive ? (x.Name == name) : x.Name.InvariantEquals(name));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and caches) <see cref="FieldInfo"/> discoverable in the current <see cref="AppDomain"/> for a given <paramref name="type"/>.
|
||||
@@ -222,7 +213,7 @@ namespace Umbraco.Core
|
||||
type,
|
||||
x => type
|
||||
.GetFields(BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(y => !y.IsInitOnly)
|
||||
.Where(y => y.IsInitOnly == false)
|
||||
.ToArray());
|
||||
}
|
||||
|
||||
@@ -240,13 +231,12 @@ namespace Umbraco.Core
|
||||
new Tuple<Type, bool, bool, bool>(type, mustRead, mustWrite, includeIndexed),
|
||||
x => type
|
||||
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(y => (!mustRead || y.CanRead)
|
||||
&& (!mustWrite || y.CanWrite)
|
||||
&& (includeIndexed || !y.GetIndexParameters().Any()))
|
||||
.Where(y => (mustRead == false || y.CanRead)
|
||||
&& (mustWrite == false || y.CanWrite)
|
||||
&& (includeIndexed || y.GetIndexParameters().Any() == false))
|
||||
.ToArray());
|
||||
}
|
||||
|
||||
|
||||
#region Match Type
|
||||
|
||||
//TODO: Need to determine if these methods should replace/combine/merge etc with IsTypeAssignableFrom, IsAssignableFromGeneric
|
||||
@@ -337,9 +327,9 @@ namespace Umbraco.Core
|
||||
|
||||
// not a generic type, not a generic parameter
|
||||
// so normal class or interface
|
||||
// fixme structs? enums? array types?
|
||||
// about primitive types, value types, etc:
|
||||
// http://stackoverflow.com/questions/1827425/how-to-check-programatically-if-a-type-is-a-struct-or-a-class
|
||||
// if it's a primitive type... it needs to be ==
|
||||
|
||||
if (implementation == contract) return true;
|
||||
if (contract.IsClass && implementation.IsClass && implementation.IsSubclassOf(contract)) return true;
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Umbraco.Tests.CodeFirst
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -84,10 +84,7 @@ namespace Umbraco.Tests.CodeFirst
|
||||
var foundTypes = _pluginManager.ResolveContentTypeBaseTypes();
|
||||
|
||||
Assert.That(foundTypes.Count(), Is.EqualTo(15));
|
||||
Assert.AreEqual(1,
|
||||
_pluginManager.GetTypeLists()
|
||||
.Count(x => x.IsTypeList<ContentTypeBase>(PluginManager.TypeResolutionKind.FindAllTypes)));
|
||||
Assert.AreEqual(1, _pluginManager.TypeLists.Count(x => x.BaseType == typeof (ContentTypeBase) && x.AttributeType == null));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ using Umbraco.Core.Profiling;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using umbraco.DataLayer;
|
||||
using umbraco.editorControls;
|
||||
using umbraco.interfaces;
|
||||
using umbraco.MacroEngines;
|
||||
using umbraco.uicontrols;
|
||||
using Umbraco.Web;
|
||||
@@ -34,14 +35,14 @@ namespace Umbraco.Tests.Plugins
|
||||
public void Initialize()
|
||||
{
|
||||
//this ensures its reset
|
||||
_manager = new PluginManager(new ActivatorServiceProvider(), new NullCacheProvider(),
|
||||
_manager = new PluginManager(new ActivatorServiceProvider(), new NullCacheProvider(),
|
||||
new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>()));
|
||||
|
||||
//for testing, we'll specify which assemblies are scanned for the PluginTypeResolver
|
||||
//TODO: Should probably update this so it only searches this assembly and add custom types to be found
|
||||
_manager.AssembliesToScan = new[]
|
||||
{
|
||||
this.GetType().Assembly,
|
||||
this.GetType().Assembly,
|
||||
typeof(ApplicationStartupHandler).Assembly,
|
||||
typeof(SqlCEHelper).Assembly,
|
||||
typeof(CMSNode).Assembly,
|
||||
@@ -160,7 +161,7 @@ namespace Umbraco.Tests.Plugins
|
||||
public void Detect_Legacy_Plugin_File_List()
|
||||
{
|
||||
var tempFolder = IOHelper.MapPath("~/App_Data/TEMP/PluginCache");
|
||||
|
||||
|
||||
var filePath= Path.Combine(tempFolder, string.Format("umbraco-plugins.{0}.list", NetworkHelper.FileSafeMachineName));
|
||||
|
||||
File.WriteAllText(filePath, @"<?xml version=""1.0"" encoding=""utf-8""?>
|
||||
@@ -169,12 +170,11 @@ namespace Umbraco.Tests.Plugins
|
||||
<add type=""umbraco.macroCacheRefresh, umbraco, Version=6.0.0.0, Culture=neutral, PublicKeyToken=null"" />
|
||||
</baseType>
|
||||
</plugins>");
|
||||
|
||||
Assert.IsTrue(_manager.DetectLegacyPluginListFile());
|
||||
|
||||
Assert.IsEmpty(_manager.ReadCache()); // uber-legacy cannot be read
|
||||
|
||||
File.Delete(filePath);
|
||||
|
||||
//now create a valid one
|
||||
File.WriteAllText(filePath, @"<?xml version=""1.0"" encoding=""utf-8""?>
|
||||
<plugins>
|
||||
<baseType type=""umbraco.interfaces.ICacheRefresher"" resolutionType=""FindAllTypes"">
|
||||
@@ -182,19 +182,32 @@ namespace Umbraco.Tests.Plugins
|
||||
</baseType>
|
||||
</plugins>");
|
||||
|
||||
Assert.IsFalse(_manager.DetectLegacyPluginListFile());
|
||||
Assert.IsEmpty(_manager.ReadCache()); // legacy cannot be read
|
||||
|
||||
File.Delete(filePath);
|
||||
|
||||
File.WriteAllText(filePath, @"IContentFinder
|
||||
|
||||
MyContentFinder
|
||||
AnotherContentFinder
|
||||
|
||||
");
|
||||
|
||||
Assert.IsNotNull(_manager.ReadCache()); // works
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Create_Cached_Plugin_File()
|
||||
{
|
||||
var types = new[] { typeof(PluginManager), typeof(PluginManagerTests), typeof(UmbracoContext) };
|
||||
var types = new[] { typeof (PluginManager), typeof (PluginManagerTests), typeof (UmbracoContext) };
|
||||
|
||||
//yes this is silly, none of these types inherit from string, but this is just to test the xml file format
|
||||
_manager.UpdateCachedPluginsFile<string>(types, PluginManager.TypeResolutionKind.FindAllTypes);
|
||||
var typeList1 = new PluginManager.TypeList(typeof (object), null);
|
||||
foreach (var type in types) typeList1.Add(type);
|
||||
_manager.AddTypeList(typeList1);
|
||||
_manager.WriteCache();
|
||||
|
||||
var plugins = _manager.TryGetCachedPluginsFromFile<string>(PluginManager.TypeResolutionKind.FindAllTypes);
|
||||
var diffType = _manager.TryGetCachedPluginsFromFile<string>(PluginManager.TypeResolutionKind.FindAttributedTypes);
|
||||
var plugins = _manager.TryGetCached(typeof (object), null);
|
||||
var diffType = _manager.TryGetCached(typeof (object), typeof (ObsoleteAttribute));
|
||||
|
||||
Assert.IsTrue(plugins.Success);
|
||||
//this will be false since there is no cache of that type resolution kind
|
||||
@@ -210,7 +223,7 @@ namespace Umbraco.Tests.Plugins
|
||||
public void PluginHash_From_String()
|
||||
{
|
||||
var s = "hello my name is someone".GetHashCode().ToString("x", CultureInfo.InvariantCulture);
|
||||
var output = PluginManager.ConvertPluginsHashFromHex(s);
|
||||
var output = PluginManager.ConvertHashToInt64(s);
|
||||
Assert.AreNotEqual(0, output);
|
||||
}
|
||||
|
||||
@@ -240,7 +253,7 @@ namespace Umbraco.Tests.Plugins
|
||||
var list1 = new[] { f1, f2, f3, f4, f5, f6 };
|
||||
var list2 = new[] { f1, f3, f5 };
|
||||
var list3 = new[] { f1, f3, f5, f7 };
|
||||
|
||||
|
||||
//Act
|
||||
var hash1 = PluginManager.GetFileHash(list1, new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>()));
|
||||
var hash2 = PluginManager.GetFileHash(list2, new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>()));
|
||||
@@ -259,9 +272,7 @@ namespace Umbraco.Tests.Plugins
|
||||
{
|
||||
var foundTypes1 = _manager.ResolveFindMeTypes();
|
||||
var foundTypes2 = _manager.ResolveFindMeTypes();
|
||||
Assert.AreEqual(1,
|
||||
_manager.GetTypeLists()
|
||||
.Count(x => x.IsTypeList<IFindMe>(PluginManager.TypeResolutionKind.FindAllTypes)));
|
||||
Assert.AreEqual(1, _manager.TypeLists.Count(x => x.BaseType == typeof(IFindMe) && x.AttributeType == null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -344,20 +355,20 @@ namespace Umbraco.Tests.Plugins
|
||||
{
|
||||
var types = new HashSet<PluginManager.TypeList>();
|
||||
|
||||
var propEditors = new PluginManager.TypeList<PropertyEditor>(PluginManager.TypeResolutionKind.FindAllTypes);
|
||||
propEditors.AddType(typeof(LabelPropertyEditor));
|
||||
var propEditors = new PluginManager.TypeList(typeof (PropertyEditor), null);
|
||||
propEditors.Add(typeof(LabelPropertyEditor));
|
||||
types.Add(propEditors);
|
||||
|
||||
var found = types.SingleOrDefault(x => x.IsTypeList<PropertyEditor>(PluginManager.TypeResolutionKind.FindAllTypes));
|
||||
var found = types.SingleOrDefault(x => x.BaseType == typeof (PropertyEditor) && x.AttributeType == null);
|
||||
|
||||
Assert.IsNotNull(found);
|
||||
|
||||
//This should not find a type list of this type
|
||||
var shouldNotFind = types.SingleOrDefault(x => x.IsTypeList<IParameterEditor>(PluginManager.TypeResolutionKind.FindAllTypes));
|
||||
var shouldNotFind = types.SingleOrDefault(x => x.BaseType == typeof (IParameterEditor) && x.AttributeType == null);
|
||||
|
||||
Assert.IsNull(shouldNotFind);
|
||||
}
|
||||
|
||||
|
||||
[XsltExtension("Blah.Blah")]
|
||||
public class MyXsltExtension
|
||||
{
|
||||
@@ -371,7 +382,7 @@ namespace Umbraco.Tests.Plugins
|
||||
|
||||
}
|
||||
|
||||
public interface IFindMe
|
||||
public interface IFindMe : IDiscoverable
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -26,11 +26,11 @@ using Umbraco.Web.BaseRest;
|
||||
|
||||
namespace Umbraco.Tests.Plugins
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Tests for typefinder
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
[TestFixture]
|
||||
public class TypeFinderTests
|
||||
{
|
||||
/// <summary>
|
||||
@@ -43,7 +43,7 @@ namespace Umbraco.Tests.Plugins
|
||||
{
|
||||
_assemblies = new[]
|
||||
{
|
||||
this.GetType().Assembly,
|
||||
this.GetType().Assembly,
|
||||
typeof(ApplicationStartupHandler).Assembly,
|
||||
typeof(SqlCEHelper).Assembly,
|
||||
typeof(CMSNode).Assembly,
|
||||
@@ -75,7 +75,7 @@ namespace Umbraco.Tests.Plugins
|
||||
[Test]
|
||||
public void Find_Classes_Of_Type()
|
||||
{
|
||||
var typesFound = TypeFinder.FindClassesOfType<IApplicationStartupHandler>(_assemblies);
|
||||
var typesFound = TypeFinder.FindClassesOfType<IApplicationStartupHandler>(_assemblies);
|
||||
var originalTypesFound = TypeFinderOriginal.FindClassesOfType<IApplicationStartupHandler>(_assemblies);
|
||||
|
||||
Assert.AreEqual(originalTypesFound.Count(), typesFound.Count());
|
||||
@@ -118,7 +118,7 @@ namespace Umbraco.Tests.Plugins
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
[Ignore]
|
||||
@@ -149,7 +149,7 @@ namespace Umbraco.Tests.Plugins
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class MyTag : ITag
|
||||
@@ -161,7 +161,7 @@ namespace Umbraco.Tests.Plugins
|
||||
|
||||
public class MySuperTag : MyTag
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
|
||||
@@ -203,7 +203,7 @@ namespace Umbraco.Tests.Plugins
|
||||
/// This is a modified version of: http://www.dominicpettifer.co.uk/Blog/44/how-to-get-a-reference-to-all-assemblies-in-the--bin-folder
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// We do this because we cannot use AppDomain.Current.GetAssemblies() as this will return only assemblies that have been
|
||||
/// We do this because we cannot use AppDomain.Current.GetAssemblies() as this will return only assemblies that have been
|
||||
/// loaded in the CLR, not all assemblies.
|
||||
/// See these threads:
|
||||
/// http://issues.umbraco.org/issue/U5-198
|
||||
@@ -329,8 +329,8 @@ namespace Umbraco.Tests.Plugins
|
||||
}
|
||||
catch (SecurityException)
|
||||
{
|
||||
//we will just ignore this because this will fail
|
||||
//in medium trust for system assemblies, we get an exception but we just want to continue until we get to
|
||||
//we will just ignore this because this will fail
|
||||
//in medium trust for system assemblies, we get an exception but we just want to continue until we get to
|
||||
//an assembly that is ok.
|
||||
}
|
||||
}
|
||||
@@ -347,9 +347,9 @@ namespace Umbraco.Tests.Plugins
|
||||
}
|
||||
catch (SecurityException)
|
||||
{
|
||||
//we will just ignore this because if we are trying to do a call to:
|
||||
//we will just ignore this because if we are trying to do a call to:
|
||||
// AssemblyName.ReferenceMatchesDefinition(a.GetName(), assemblyName)))
|
||||
//in medium trust for system assemblies, we get an exception but we just want to continue until we get to
|
||||
//in medium trust for system assemblies, we get an exception but we just want to continue until we get to
|
||||
//an assembly that is ok.
|
||||
}
|
||||
}
|
||||
@@ -361,7 +361,7 @@ namespace Umbraco.Tests.Plugins
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a list of found local Assemblies excluding the known assemblies we don't want to scan
|
||||
/// Return a list of found local Assemblies excluding the known assemblies we don't want to scan
|
||||
/// and exluding the ones passed in and excluding the exclusion list filter, the results of this are
|
||||
/// cached for perforance reasons.
|
||||
/// </summary>
|
||||
@@ -429,7 +429,7 @@ namespace Umbraco.Tests.Plugins
|
||||
"RouteDebugger,",
|
||||
"SqlCE4Umbraco,",
|
||||
"umbraco.datalayer,",
|
||||
"umbraco.interfaces,",
|
||||
"umbraco.interfaces,",
|
||||
"umbraco.providers,",
|
||||
"Umbraco.Web.UI,",
|
||||
"umbraco.webservices",
|
||||
@@ -631,5 +631,5 @@ namespace Umbraco.Tests.Plugins
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -62,7 +62,7 @@ namespace Umbraco.Tests.TestHelpers
|
||||
public override void TearDown()
|
||||
{
|
||||
base.TearDown();
|
||||
|
||||
|
||||
// reset settings
|
||||
SettingsForTests.Reset();
|
||||
UmbracoContext.Current = null;
|
||||
@@ -119,7 +119,7 @@ namespace Umbraco.Tests.TestHelpers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// By default this returns false which means the plugin manager will not be reset so it doesn't need to re-scan
|
||||
/// By default this returns false which means the plugin manager will not be reset so it doesn't need to re-scan
|
||||
/// all of the assemblies. Inheritors can override this if plugin manager resetting is required, generally needs
|
||||
/// to be set to true if the SetupPluginManager has been overridden.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
internal interface IEditorValidator
|
||||
internal interface IEditorValidator : IDiscoverable
|
||||
{
|
||||
Type ModelType { get; }
|
||||
IEnumerable<ValidationResult> Validate(object model);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using umbraco.interfaces;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Web.HealthCheck
|
||||
@@ -9,7 +10,7 @@ namespace Umbraco.Web.HealthCheck
|
||||
/// The abstract health check class
|
||||
/// </summary>
|
||||
[DataContract(Name = "healtCheck", Namespace = "")]
|
||||
public abstract class HealthCheck
|
||||
public abstract class HealthCheck : IDiscoverable
|
||||
{
|
||||
protected HealthCheck(HealthCheckContext healthCheckContext)
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@ using umbraco;
|
||||
|
||||
namespace Umbraco.Web.Media
|
||||
{
|
||||
[Obsolete("This is no longer used and will be removed in future versions")]
|
||||
public class ImageUrl
|
||||
{
|
||||
[Obsolete("Use TryGetImageUrl() instead")]
|
||||
|
||||
@@ -8,9 +8,10 @@ using Umbraco.Web.Media.ImageUrlProviders;
|
||||
|
||||
namespace Umbraco.Web.Media
|
||||
{
|
||||
internal sealed class ImageUrlProviderResolver : ManyObjectsResolverBase<ImageUrlProviderResolver, IImageUrlProvider>
|
||||
[Obsolete("IImageUrlProvider is no longer used and will be removed in future versions")]
|
||||
internal sealed class ImageUrlProviderResolver : LazyManyObjectsResolverBase<ImageUrlProviderResolver, IImageUrlProvider>
|
||||
{
|
||||
internal ImageUrlProviderResolver(IServiceProvider serviceProvider, ILogger logger, IEnumerable<Type> value)
|
||||
internal ImageUrlProviderResolver(IServiceProvider serviceProvider, ILogger logger, Func<IEnumerable<Type>> value)
|
||||
: base(serviceProvider, logger, value)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@ using umbraco.BusinessLogic.Utils;
|
||||
|
||||
namespace Umbraco.Web.Media.ThumbnailProviders
|
||||
{
|
||||
public sealed class ThumbnailProvidersResolver : ManyObjectsResolverBase<ThumbnailProvidersResolver, IThumbnailProvider>
|
||||
[Obsolete("Thumbnails are generated by ImageProcessor, use that instead")]
|
||||
public sealed class ThumbnailProvidersResolver : LazyManyObjectsResolverBase<ThumbnailProvidersResolver, IThumbnailProvider>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
@@ -20,7 +21,7 @@ namespace Umbraco.Web.Media.ThumbnailProviders
|
||||
/// <param name="serviceProvider"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="providers"></param>
|
||||
internal ThumbnailProvidersResolver(IServiceProvider serviceProvider, ILogger logger, IEnumerable<Type> providers)
|
||||
internal ThumbnailProvidersResolver(IServiceProvider serviceProvider, ILogger logger, Func<IEnumerable<Type>> providers)
|
||||
: base(serviceProvider, logger, providers)
|
||||
{
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Web.Mvc;
|
||||
using umbraco.interfaces;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Services;
|
||||
@@ -12,7 +13,7 @@ namespace Umbraco.Web.Mvc
|
||||
/// <summary>
|
||||
/// A base class for all plugin controllers to inherit from
|
||||
/// </summary>
|
||||
public abstract class PluginController : Controller
|
||||
public abstract class PluginController : Controller, IDiscoverable
|
||||
{
|
||||
/// <summary>
|
||||
/// stores the metadata about plugin controllers
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Linq;
|
||||
using System.Web.Http;
|
||||
using System.Web.Http.ModelBinding;
|
||||
using umbraco.interfaces;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Validation;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
@@ -11,7 +12,7 @@ namespace Umbraco.Web.WebApi
|
||||
/// <summary>
|
||||
/// The base class for auto-routed API controllers for Umbraco
|
||||
/// </summary>
|
||||
public abstract class UmbracoApiController : UmbracoApiControllerBase
|
||||
public abstract class UmbracoApiController : UmbracoApiControllerBase, IDiscoverable
|
||||
{
|
||||
protected UmbracoApiController()
|
||||
{
|
||||
|
||||
@@ -533,11 +533,11 @@ namespace Umbraco.Web
|
||||
|
||||
ThumbnailProvidersResolver.Current = new ThumbnailProvidersResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
PluginManager.ResolveThumbnailProviders());
|
||||
() => PluginManager.ResolveThumbnailProviders());
|
||||
|
||||
ImageUrlProviderResolver.Current = new ImageUrlProviderResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
PluginManager.ResolveImageUrlProviders());
|
||||
() => PluginManager.ResolveImageUrlProviders());
|
||||
|
||||
CultureDictionaryFactoryResolver.Current = new CultureDictionaryFactoryResolver(
|
||||
new DefaultCultureDictionaryFactory());
|
||||
|
||||
@@ -15,7 +15,7 @@ using Tag = umbraco.cms.businesslogic.Tags.Tag;
|
||||
namespace Umbraco.Web.WebServices
|
||||
{
|
||||
//TODO: Can we convert this to MVC please instead of /base?
|
||||
|
||||
[Obsolete("Thumbnails are generated by ImageProcessor, use that instead")]
|
||||
[RestExtension("FolderBrowserService")]
|
||||
public class FolderBrowserService
|
||||
{
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System.Web.UI;
|
||||
using System;
|
||||
using System.Web.UI;
|
||||
using System.Web.UI.HtmlControls;
|
||||
using Umbraco.Core.Media;
|
||||
using Umbraco.Web.Media;
|
||||
|
||||
namespace umbraco.presentation.templateControls
|
||||
{
|
||||
[Obsolete("This is no longer used and will be removed in future versions")]
|
||||
public class Image : HtmlImage
|
||||
{
|
||||
public string NodeId { get; set; }
|
||||
|
||||
@@ -16,9 +16,8 @@ namespace umbraco.businesslogic
|
||||
/// <param name="resolver"></param>
|
||||
/// <returns></returns>
|
||||
internal static IEnumerable<Type> ResolveApplications(this PluginManager resolver)
|
||||
{
|
||||
//don't cache the result of this because it is only used once during app startup, caching will just add a bit more mem overhead for no reason
|
||||
return resolver.ResolveTypesWithAttribute<IApplication, ApplicationAttribute>(cacheResult:false);
|
||||
{
|
||||
return resolver.ResolveTypesWithAttribute<IApplication, ApplicationAttribute>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -28,8 +27,7 @@ namespace umbraco.businesslogic
|
||||
/// <returns></returns>
|
||||
internal static IEnumerable<Type> ResolveAttributedTrees(this PluginManager resolver)
|
||||
{
|
||||
//don't cache the result of this because it is only used once during app startup, caching will just add a bit more mem overhead for no reason
|
||||
return resolver.ResolveTypesWithAttribute<ITree, TreeAttribute>(cacheResult:false);
|
||||
return resolver.ResolveTypesWithAttribute<ITree, TreeAttribute>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,40 +35,10 @@ namespace umbraco.BusinessLogic.Actions
|
||||
public class Action
|
||||
{
|
||||
private static readonly Dictionary<string, string> ActionJs = new Dictionary<string, string>();
|
||||
|
||||
private static readonly object Lock = new object();
|
||||
|
||||
static Action()
|
||||
{
|
||||
ReRegisterActionsAndHandlers();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used when an IAction or IActionHandler is installed into the system
|
||||
/// and needs to be loaded into memory.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// TODO: this shouldn't be needed... we should restart the app pool when a package is installed!
|
||||
/// </remarks>
|
||||
|
||||
[Obsolete("This no longer performs any action there is never a reason to rescan because the app domain will be restarted if new IActions are added because they are included in assemblies")]
|
||||
public static void ReRegisterActionsAndHandlers()
|
||||
{
|
||||
lock (Lock)
|
||||
{
|
||||
// NOTE use the DirtyBackdoor to change the resolution configuration EXCLUSIVELY
|
||||
// ie do NOT do ANYTHING else while holding the backdoor, because while it is open
|
||||
// the whole resolution system is locked => nothing can work properly => deadlocks
|
||||
|
||||
var newResolver = new ActionsResolver(
|
||||
new ActivatorServiceProvider(), LoggerResolver.Current.Logger,
|
||||
() => TypeFinder.FindClassesOfType<IAction>(PluginManager.Current.AssembliesToScan));
|
||||
|
||||
using (Umbraco.Core.ObjectResolution.Resolution.DirtyBackdoorToConfiguration)
|
||||
{
|
||||
ActionsResolver.Reset(false); // and do NOT reset the whole resolution!
|
||||
ActionsResolver.Current = newResolver;
|
||||
}
|
||||
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -6,7 +6,8 @@ using umbraco.interfaces;
|
||||
|
||||
namespace umbraco.cms.businesslogic.macro
|
||||
{
|
||||
public interface IMacroEngine {
|
||||
public interface IMacroEngine : IDiscoverable
|
||||
{
|
||||
string Name { get; }
|
||||
IEnumerable<string> SupportedExtensions { get; }
|
||||
IEnumerable<string> SupportedUIExtensions { get; }
|
||||
|
||||
@@ -3,11 +3,12 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using umbraco.BusinessLogic;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace umbraco.cms.businesslogic.media
|
||||
{
|
||||
[Obsolete("This interface is no longer used and will be removed from the codebase in future versions")]
|
||||
public interface IMediaFactory
|
||||
public interface IMediaFactory : IDiscoverable
|
||||
{
|
||||
List<string> Extensions { get; }
|
||||
int Priority { get; }
|
||||
|
||||
@@ -5,8 +5,8 @@ namespace umbraco.interfaces
|
||||
/// <summary>
|
||||
/// Summary description for ActionI.
|
||||
/// </summary>
|
||||
public interface IAction
|
||||
{
|
||||
public interface IAction : IDiscoverable
|
||||
{
|
||||
char Letter {get;}
|
||||
bool ShowInNotifier {get;}
|
||||
bool CanBePermissionAssigned {get;}
|
||||
|
||||
@@ -7,6 +7,6 @@ namespace umbraco.interfaces
|
||||
/// <summary>
|
||||
/// Interface for created applications in the umbraco backoffice
|
||||
/// </summary>
|
||||
public interface IApplication
|
||||
{}
|
||||
public interface IApplication : IDiscoverable
|
||||
{ }
|
||||
}
|
||||
|
||||
@@ -14,6 +14,6 @@ namespace umbraco.interfaces
|
||||
/// and bind to any custom events in the OnApplicationInitialized method.
|
||||
/// </remarks>
|
||||
[Obsolete("This interface is obsolete, use IApplicationEventHandler or ApplicationEventHandler instead")]
|
||||
public interface IApplicationStartupHandler
|
||||
public interface IApplicationStartupHandler : IDiscoverable
|
||||
{ }
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace umbraco.interfaces
|
||||
/// The IcacheRefresher Interface is used for loadbalancing.
|
||||
///
|
||||
/// </summary>
|
||||
public interface ICacheRefresher
|
||||
public interface ICacheRefresher : IDiscoverable
|
||||
{
|
||||
Guid UniqueIdentifier { get; }
|
||||
string Name { get; }
|
||||
|
||||
@@ -8,8 +8,8 @@ namespace umbraco.interfaces
|
||||
/// And finally it contains IData which manages the actual data in the Data Type
|
||||
/// </summary>
|
||||
[Obsolete("IDataType is obsolete and is no longer used, it will be removed from the codebase in future versions")]
|
||||
public interface IDataType
|
||||
{
|
||||
public interface IDataType : IDiscoverable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the id.
|
||||
/// </summary>
|
||||
|
||||
8
src/umbraco.interfaces/IDiscoverable.cs
Normal file
8
src/umbraco.interfaces/IDiscoverable.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace umbraco.interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Marks a class or an interface as discoverable by PluginManager.
|
||||
/// </summary>
|
||||
public interface IDiscoverable
|
||||
{ }
|
||||
}
|
||||
@@ -6,8 +6,8 @@ namespace umbraco.interfaces
|
||||
/// Summary description for IMacroGuiRendering.
|
||||
/// </summary>
|
||||
[Obsolete("This interface is no longer used and will be removed from the codebase in future versions")]
|
||||
public interface IMacroGuiRendering
|
||||
{
|
||||
public interface IMacroGuiRendering : IDiscoverable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the value.
|
||||
/// </summary>
|
||||
|
||||
@@ -4,7 +4,8 @@ using System.Text;
|
||||
using System.Xml;
|
||||
|
||||
namespace umbraco.interfaces {
|
||||
public interface IPackageAction {
|
||||
public interface IPackageAction : IDiscoverable
|
||||
{
|
||||
bool Execute(string packageName, XmlNode xmlData);
|
||||
string Alias();
|
||||
bool Undo(string packageName, XmlNode xmlData);
|
||||
|
||||
@@ -6,8 +6,8 @@ namespace umbraco.interfaces
|
||||
/// <summary>
|
||||
/// Interface for created application trees in the umbraco backoffice
|
||||
/// </summary>
|
||||
public interface ITree
|
||||
{
|
||||
public interface ITree : IDiscoverable
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the tree id.
|
||||
/// </summary>
|
||||
|
||||
@@ -127,6 +127,7 @@
|
||||
<Compile Include="IApplication.cs" />
|
||||
<Compile Include="IApplicationStartupHandler.cs" />
|
||||
<Compile Include="IDataFieldWithButtons.cs" />
|
||||
<Compile Include="IDiscoverable.cs" />
|
||||
<Compile Include="IProperty.cs" />
|
||||
<Compile Include="ITag.cs" />
|
||||
<Compile Include="ITaskReturnUrl.cs" />
|
||||
|
||||
Reference in New Issue
Block a user