Merge remote-tracking branch 'origin/netcore/dev' into netcore/feature/AB3649-move-manifest-stuff
This commit is contained in:
+29
-20
@@ -10,24 +10,33 @@ namespace Umbraco.Core.Cache
|
||||
/// <summary>
|
||||
/// Implements a fast <see cref="IAppCache"/> on top of a concurrent dictionary.
|
||||
/// </summary>
|
||||
internal class FastDictionaryAppCache : IAppCache
|
||||
public class FastDictionaryAppCache : IAppCache
|
||||
{
|
||||
private readonly ITypeFinder _typeFinder;
|
||||
|
||||
public FastDictionaryAppCache(ITypeFinder typeFinder)
|
||||
{
|
||||
_typeFinder = typeFinder ?? throw new ArgumentNullException(nameof(typeFinder));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the internal items dictionary, for tests only!
|
||||
/// </summary>
|
||||
internal readonly ConcurrentDictionary<string, Lazy<object>> Items = new ConcurrentDictionary<string, Lazy<object>>();
|
||||
private readonly ConcurrentDictionary<string, Lazy<object>> _items = new ConcurrentDictionary<string, Lazy<object>>();
|
||||
|
||||
public int Count => _items.Count;
|
||||
|
||||
/// <inheritdoc />
|
||||
public object Get(string cacheKey)
|
||||
{
|
||||
Items.TryGetValue(cacheKey, out var result); // else null
|
||||
_items.TryGetValue(cacheKey, out var result); // else null
|
||||
return result == null ? null : SafeLazy.GetSafeLazyValue(result); // return exceptions as null
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public object Get(string cacheKey, Func<object> getCacheItem)
|
||||
{
|
||||
var result = Items.GetOrAdd(cacheKey, k => SafeLazy.GetSafeLazy(getCacheItem));
|
||||
var result = _items.GetOrAdd(cacheKey, k => SafeLazy.GetSafeLazy(getCacheItem));
|
||||
|
||||
var value = result.Value; // will not throw (safe lazy)
|
||||
if (!(value is SafeLazy.ExceptionHolder eh))
|
||||
@@ -37,7 +46,7 @@ namespace Umbraco.Core.Cache
|
||||
// which would trick with GetSafeLazyValue, we need to remove by ourselves,
|
||||
// in order NOT to cache exceptions
|
||||
|
||||
Items.TryRemove(cacheKey, out result);
|
||||
_items.TryRemove(cacheKey, out result);
|
||||
eh.Exception.Throw(); // throw once!
|
||||
return null; // never reached
|
||||
}
|
||||
@@ -45,7 +54,7 @@ namespace Umbraco.Core.Cache
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<object> SearchByKey(string keyStartsWith)
|
||||
{
|
||||
return Items
|
||||
return _items
|
||||
.Where(kvp => kvp.Key.InvariantStartsWith(keyStartsWith))
|
||||
.Select(kvp => SafeLazy.GetSafeLazyValue(kvp.Value))
|
||||
.Where(x => x != null);
|
||||
@@ -55,7 +64,7 @@ namespace Umbraco.Core.Cache
|
||||
public IEnumerable<object> SearchByRegex(string regex)
|
||||
{
|
||||
var compiled = new Regex(regex, RegexOptions.Compiled);
|
||||
return Items
|
||||
return _items
|
||||
.Where(kvp => compiled.IsMatch(kvp.Key))
|
||||
.Select(kvp => SafeLazy.GetSafeLazyValue(kvp.Value))
|
||||
.Where(x => x != null);
|
||||
@@ -64,23 +73,23 @@ namespace Umbraco.Core.Cache
|
||||
/// <inheritdoc />
|
||||
public void Clear()
|
||||
{
|
||||
Items.Clear();
|
||||
_items.Clear();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Clear(string key)
|
||||
{
|
||||
Items.TryRemove(key, out _);
|
||||
_items.TryRemove(key, out _);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ClearOfType(string typeName)
|
||||
{
|
||||
var type = TypeFinder.GetTypeByName(typeName);
|
||||
var type = _typeFinder.GetTypeByName(typeName);
|
||||
if (type == null) return;
|
||||
var isInterface = type.IsInterface;
|
||||
|
||||
foreach (var kvp in Items
|
||||
foreach (var kvp in _items
|
||||
.Where(x =>
|
||||
{
|
||||
// entry.Value is Lazy<object> and not null, its value may be null
|
||||
@@ -92,7 +101,7 @@ namespace Umbraco.Core.Cache
|
||||
// otherwise remove exact types (not inherited types)
|
||||
return value == null || (isInterface ? (type.IsInstanceOfType(value)) : (value.GetType() == type));
|
||||
}))
|
||||
Items.TryRemove(kvp.Key, out _);
|
||||
_items.TryRemove(kvp.Key, out _);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -101,7 +110,7 @@ namespace Umbraco.Core.Cache
|
||||
var typeOfT = typeof(T);
|
||||
var isInterface = typeOfT.IsInterface;
|
||||
|
||||
foreach (var kvp in Items
|
||||
foreach (var kvp in _items
|
||||
.Where(x =>
|
||||
{
|
||||
// entry.Value is Lazy<object> and not null, its value may be null
|
||||
@@ -114,7 +123,7 @@ namespace Umbraco.Core.Cache
|
||||
// otherwise remove exact types (not inherited types)
|
||||
return value == null || (isInterface ? (value is T) : (value.GetType() == typeOfT));
|
||||
}))
|
||||
Items.TryRemove(kvp.Key, out _);
|
||||
_items.TryRemove(kvp.Key, out _);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -123,7 +132,7 @@ namespace Umbraco.Core.Cache
|
||||
var typeOfT = typeof(T);
|
||||
var isInterface = typeOfT.IsInterface;
|
||||
|
||||
foreach (var kvp in Items
|
||||
foreach (var kvp in _items
|
||||
.Where(x =>
|
||||
{
|
||||
// entry.Value is Lazy<object> and not null, its value may be null
|
||||
@@ -139,24 +148,24 @@ namespace Umbraco.Core.Cache
|
||||
// run predicate on the 'public key' part only, ie without prefix
|
||||
&& predicate(x.Key, (T)value);
|
||||
}))
|
||||
Items.TryRemove(kvp.Key, out _);
|
||||
_items.TryRemove(kvp.Key, out _);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ClearByKey(string keyStartsWith)
|
||||
{
|
||||
foreach (var ikvp in Items
|
||||
foreach (var ikvp in _items
|
||||
.Where(kvp => kvp.Key.InvariantStartsWith(keyStartsWith)))
|
||||
Items.TryRemove(ikvp.Key, out _);
|
||||
_items.TryRemove(ikvp.Key, out _);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ClearByRegex(string regex)
|
||||
{
|
||||
var compiled = new Regex(regex, RegexOptions.Compiled);
|
||||
foreach (var ikvp in Items
|
||||
foreach (var ikvp in _items
|
||||
.Where(kvp => compiled.IsMatch(kvp.Key)))
|
||||
Items.TryRemove(ikvp.Key, out _);
|
||||
_items.TryRemove(ikvp.Key, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-2
@@ -10,8 +10,15 @@ namespace Umbraco.Core.Cache
|
||||
/// <summary>
|
||||
/// Provides a base class to fast, dictionary-based <see cref="IAppCache"/> implementations.
|
||||
/// </summary>
|
||||
internal abstract class FastDictionaryAppCacheBase : IAppCache
|
||||
public abstract class FastDictionaryAppCacheBase : IAppCache
|
||||
{
|
||||
private readonly ITypeFinder _typeFinder;
|
||||
|
||||
protected FastDictionaryAppCacheBase(ITypeFinder typeFinder)
|
||||
{
|
||||
_typeFinder = typeFinder ?? throw new ArgumentNullException(nameof(typeFinder));
|
||||
}
|
||||
|
||||
// prefix cache keys so we know which one are ours
|
||||
protected const string CacheItemPrefix = "umbrtmche";
|
||||
|
||||
@@ -116,7 +123,7 @@ namespace Umbraco.Core.Cache
|
||||
/// <inheritdoc />
|
||||
public virtual void ClearOfType(string typeName)
|
||||
{
|
||||
var type = TypeFinder.GetTypeByName(typeName);
|
||||
var type = _typeFinder.GetTypeByName(typeName);
|
||||
if (type == null) return;
|
||||
var isInterface = type.IsInterface;
|
||||
try
|
||||
+31
-37
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
@@ -15,37 +16,29 @@ namespace Umbraco.Core.Cache
|
||||
/// or no Items...) then this cache acts as a pass-through and does not cache
|
||||
/// anything.</para>
|
||||
/// </remarks>
|
||||
internal class HttpRequestAppCache : FastDictionaryAppCacheBase
|
||||
public class HttpRequestAppCache : FastDictionaryAppCacheBase
|
||||
{
|
||||
private readonly HttpContextBase _context;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HttpRequestAppCache"/> class with a context, for unit tests!
|
||||
/// </summary>
|
||||
public HttpRequestAppCache(HttpContextBase context)
|
||||
public HttpRequestAppCache(Func<IDictionary> requestItems, ITypeFinder typeFinder) : base(typeFinder)
|
||||
{
|
||||
_context = context;
|
||||
ContextItems = requestItems;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HttpRequestAppCache"/> class.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Will use HttpContext.Current.</para>
|
||||
/// TODO: https://github.com/umbraco/Umbraco-CMS/issues/4239 - use IHttpContextAccessor NOT HttpContext.Current
|
||||
/// </remarks>
|
||||
public HttpRequestAppCache()
|
||||
{ }
|
||||
private Func<IDictionary> ContextItems { get; }
|
||||
|
||||
private IDictionary ContextItems => _context?.Items ?? HttpContext.Current?.Items;
|
||||
|
||||
private bool HasContextItems => _context?.Items != null || HttpContext.Current != null;
|
||||
private bool TryGetContextItems(out IDictionary items)
|
||||
{
|
||||
items = ContextItems?.Invoke();
|
||||
return items != null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object Get(string key, Func<object> factory)
|
||||
{
|
||||
//no place to cache so just return the callback result
|
||||
if (HasContextItems == false) return factory();
|
||||
if (!TryGetContextItems(out var items)) return factory();
|
||||
|
||||
key = GetCacheKey(key);
|
||||
|
||||
@@ -54,7 +47,7 @@ namespace Umbraco.Core.Cache
|
||||
try
|
||||
{
|
||||
EnterWriteLock();
|
||||
result = ContextItems[key] as Lazy<object>; // null if key not found
|
||||
result = items[key] as Lazy<object>; // null if key not found
|
||||
|
||||
// cannot create value within the lock, so if result.IsValueCreated is false, just
|
||||
// do nothing here - means that if creation throws, a race condition could cause
|
||||
@@ -63,7 +56,7 @@ namespace Umbraco.Core.Cache
|
||||
if (result == null || SafeLazy.GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null
|
||||
{
|
||||
result = SafeLazy.GetSafeLazy(factory);
|
||||
ContextItems[key] = result;
|
||||
items[key] = result;
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -89,22 +82,22 @@ namespace Umbraco.Core.Cache
|
||||
{
|
||||
const string prefix = CacheItemPrefix + "-";
|
||||
|
||||
if (HasContextItems == false) return Enumerable.Empty<DictionaryEntry>();
|
||||
if (!TryGetContextItems(out var items)) return Enumerable.Empty<DictionaryEntry>();
|
||||
|
||||
return ContextItems.Cast<DictionaryEntry>()
|
||||
return items.Cast<DictionaryEntry>()
|
||||
.Where(x => x.Key is string s && s.StartsWith(prefix));
|
||||
}
|
||||
|
||||
protected override void RemoveEntry(string key)
|
||||
{
|
||||
if (HasContextItems == false) return;
|
||||
if (!TryGetContextItems(out var items)) return;
|
||||
|
||||
ContextItems.Remove(key);
|
||||
items.Remove(key);
|
||||
}
|
||||
|
||||
protected override object GetEntry(string key)
|
||||
{
|
||||
return HasContextItems ? ContextItems[key] : null;
|
||||
return !TryGetContextItems(out var items) ? null : items[key];
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -117,26 +110,27 @@ namespace Umbraco.Core.Cache
|
||||
|
||||
protected override void EnterWriteLock()
|
||||
{
|
||||
if (HasContextItems)
|
||||
{
|
||||
// note: cannot keep 'entered' as a class variable here,
|
||||
// since there is one per request - so storing it within
|
||||
// ContextItems - which is locked, so this should be safe
|
||||
if (!TryGetContextItems(out var items)) return;
|
||||
|
||||
var entered = false;
|
||||
Monitor.Enter(ContextItems.SyncRoot, ref entered);
|
||||
ContextItems[ContextItemsLockKey] = entered;
|
||||
}
|
||||
// note: cannot keep 'entered' as a class variable here,
|
||||
// since there is one per request - so storing it within
|
||||
// ContextItems - which is locked, so this should be safe
|
||||
|
||||
var entered = false;
|
||||
Monitor.Enter(items.SyncRoot, ref entered);
|
||||
items[ContextItemsLockKey] = entered;
|
||||
}
|
||||
|
||||
protected override void ExitReadLock() => ExitWriteLock();
|
||||
|
||||
protected override void ExitWriteLock()
|
||||
{
|
||||
var entered = (bool?) ContextItems[ContextItemsLockKey] ?? false;
|
||||
if (!TryGetContextItems(out var items)) return;
|
||||
|
||||
var entered = (bool?)items[ContextItemsLockKey] ?? false;
|
||||
if (entered)
|
||||
Monitor.Exit(ContextItems.SyncRoot);
|
||||
ContextItems.Remove(ContextItemsLockKey);
|
||||
Monitor.Exit(items.SyncRoot);
|
||||
items.Remove(ContextItemsLockKey);
|
||||
}
|
||||
|
||||
#endregion
|
||||
+5
-3
@@ -13,13 +13,15 @@ namespace Umbraco.Core.Cache
|
||||
/// </summary>
|
||||
public class ObjectCacheAppCache : IAppPolicyCache
|
||||
{
|
||||
private readonly ITypeFinder _typeFinder;
|
||||
private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ObjectCacheAppCache"/>.
|
||||
/// </summary>
|
||||
public ObjectCacheAppCache()
|
||||
public ObjectCacheAppCache(ITypeFinder typeFinder)
|
||||
{
|
||||
_typeFinder = typeFinder ?? throw new ArgumentNullException(nameof(typeFinder));
|
||||
// the MemoryCache is created with name "in-memory". That name is
|
||||
// used to retrieve configuration options. It does not identify the memory cache, i.e.
|
||||
// each instance of this class has its own, independent, memory cache.
|
||||
@@ -29,7 +31,7 @@ namespace Umbraco.Core.Cache
|
||||
/// <summary>
|
||||
/// Gets the internal memory cache, for tests only!
|
||||
/// </summary>
|
||||
internal ObjectCache MemoryCache { get; private set; }
|
||||
public ObjectCache MemoryCache { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public object Get(string key)
|
||||
@@ -178,7 +180,7 @@ namespace Umbraco.Core.Cache
|
||||
/// <inheritdoc />
|
||||
public virtual void ClearOfType(string typeName)
|
||||
{
|
||||
var type = TypeFinder.GetTypeByName(typeName);
|
||||
var type = _typeFinder.GetTypeByName(typeName);
|
||||
if (type == null) return;
|
||||
var isInterface = type.IsInterface;
|
||||
try
|
||||
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to find objects by implemented types, names and/or attributes
|
||||
/// </summary>
|
||||
public interface ITypeFinder
|
||||
{
|
||||
Type GetTypeByName(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Return a list of found local Assemblies that Umbraco should scan for type finding
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
IEnumerable<Assembly> AssembliesToScan { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Finds any classes derived from the assignTypeFrom Type that contain the attribute TAttribute
|
||||
/// </summary>
|
||||
/// <param name="assignTypeFrom"></param>
|
||||
/// <param name="attributeType"></param>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<Type> FindClassesOfTypeWithAttribute(
|
||||
Type assignTypeFrom,
|
||||
Type attributeType,
|
||||
IEnumerable<Assembly> assemblies = null,
|
||||
bool onlyConcreteClasses = true);
|
||||
|
||||
/// <summary>
|
||||
/// Returns all types found of in the assemblies specified of type T
|
||||
/// </summary>
|
||||
/// <param name="assignTypeFrom"></param>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<Type> FindClassesOfType(Type assignTypeFrom, IEnumerable<Assembly> assemblies = null, bool onlyConcreteClasses = true);
|
||||
|
||||
/// <summary>
|
||||
/// Finds any classes with the attribute.
|
||||
/// </summary>
|
||||
/// <param name="attributeType">The attribute type </param>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <param name="onlyConcreteClasses">if set to <c>true</c> only concrete classes.</param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<Type> FindClassesWithAttribute(
|
||||
Type attributeType,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses);
|
||||
}
|
||||
}
|
||||
+160
-265
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
@@ -6,98 +7,30 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using System.Web.Compilation;
|
||||
using System.Web.Hosting;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
/// <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
|
||||
/// <inheritdoc cref="ITypeFinder"/>
|
||||
public class TypeFinder : ITypeFinder
|
||||
{
|
||||
private static volatile HashSet<Assembly> _localFilteredAssemblyCache;
|
||||
private static readonly object LocalFilteredAssemblyCacheLocker = new object();
|
||||
private static readonly List<string> NotifiedLoadExceptionAssemblies = new List<string>();
|
||||
private static string[] _assembliesAcceptingLoadExceptions;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private static string[] AssembliesAcceptingLoadExceptions
|
||||
public TypeFinder(ILogger logger, ITypeFinderConfig typeFinderConfig = null)
|
||||
{
|
||||
get
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_assembliesAcceptingLoadExceptions = typeFinderConfig?.AssembliesAcceptingLoadExceptions.Where(x => !x.IsNullOrWhiteSpace()).ToArray() ?? Array.Empty<string>();
|
||||
_allAssemblies = new Lazy<HashSet<Assembly>>(() =>
|
||||
{
|
||||
if (_assembliesAcceptingLoadExceptions != null)
|
||||
return _assembliesAcceptingLoadExceptions;
|
||||
|
||||
var s = ConfigurationManager.AppSettings[Constants.AppSettings.AssembliesAcceptingLoadExceptions];
|
||||
return _assembliesAcceptingLoadExceptions = string.IsNullOrWhiteSpace(s)
|
||||
? Array.Empty<string>()
|
||||
: s.Split(',').Select(x => x.Trim()).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private static bool AcceptsLoadExceptions(Assembly a)
|
||||
{
|
||||
if (AssembliesAcceptingLoadExceptions.Length == 0)
|
||||
return false;
|
||||
if (AssembliesAcceptingLoadExceptions.Length == 1 && AssembliesAcceptingLoadExceptions[0] == "*")
|
||||
return true;
|
||||
var name = a.GetName().Name; // simple name of the assembly
|
||||
return AssembliesAcceptingLoadExceptions.Any(pattern =>
|
||||
{
|
||||
if (pattern.Length > name.Length) return false; // pattern longer than name
|
||||
if (pattern.Length == name.Length) return pattern.InvariantEquals(name); // same length, must be identical
|
||||
if (pattern[pattern.Length] != '.') return false; // pattern is shorter than name, must end with dot
|
||||
return name.StartsWith(pattern); // and name must start with pattern
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// lazily load a reference to all assemblies and only local assemblies.
|
||||
/// 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
|
||||
/// loaded in the CLR, not all assemblies.
|
||||
/// See these threads:
|
||||
/// http://issues.umbraco.org/issue/U5-198
|
||||
/// http://stackoverflow.com/questions/3552223/asp-net-appdomain-currentdomain-getassemblies-assemblies-missing-after-app
|
||||
/// http://stackoverflow.com/questions/2477787/difference-between-appdomain-getassemblies-and-buildmanager-getreferencedassembl
|
||||
/// </remarks>
|
||||
internal static HashSet<Assembly> GetAllAssemblies()
|
||||
{
|
||||
return AllAssemblies.Value;
|
||||
}
|
||||
|
||||
//Lazy access to the all assemblies list
|
||||
private static readonly Lazy<HashSet<Assembly>> AllAssemblies = new Lazy<HashSet<Assembly>>(() =>
|
||||
{
|
||||
HashSet<Assembly> assemblies = null;
|
||||
try
|
||||
{
|
||||
var isHosted = Current.IOHelper.IsHosted;
|
||||
|
||||
HashSet<Assembly> assemblies = null;
|
||||
try
|
||||
{
|
||||
if (isHosted)
|
||||
{
|
||||
assemblies = new HashSet<Assembly>(BuildManager.GetReferencedAssemblies().Cast<Assembly>());
|
||||
}
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
if (e.InnerException is SecurityException == false)
|
||||
throw;
|
||||
}
|
||||
|
||||
if (assemblies == null)
|
||||
{
|
||||
//NOTE: we cannot use AppDomain.CurrentDomain.GetAssemblies() because this only returns assemblies that have
|
||||
// already been loaded in to the app domain, instead we will look directly into the bin folder and load each one.
|
||||
var binFolder = Current.IOHelper.GetRootDirectoryBinFolder();
|
||||
var binFolder = GetRootDirectorySafe();
|
||||
var binAssemblyFiles = Directory.GetFiles(binFolder, "*.dll", SearchOption.TopDirectoryOnly).ToList();
|
||||
//var binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory;
|
||||
//var binAssemblyFiles = Directory.GetFiles(binFolder.FullName, "*.dll", SearchOption.TopDirectoryOnly).ToList();
|
||||
@@ -122,63 +55,101 @@ namespace Umbraco.Core.Composing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if for some reason they are still no assemblies, then use the AppDomain to load in already loaded assemblies.
|
||||
if (assemblies.Any() == false)
|
||||
{
|
||||
//Since we are only loading in the /bin assemblies above, we will also load in anything that's already loaded (which will include gac items)
|
||||
foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
assemblies.Add(a);
|
||||
}
|
||||
}
|
||||
|
||||
//here we are trying to get the App_Code assembly
|
||||
var fileExtensions = new[] { ".cs", ".vb" }; //only vb and cs files are supported
|
||||
var appCodeFolder = new DirectoryInfo(Current.IOHelper.MapPath(Current.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()))
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var appCodeAssembly = Assembly.Load("App_Code");
|
||||
if (assemblies.Contains(appCodeAssembly) == false) // BuildManager will find App_Code already
|
||||
assemblies.Add(appCodeAssembly);
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
{
|
||||
//this will occur if it cannot load the assembly
|
||||
Current.Logger.Error(typeof(TypeFinder), ex, "Could not load assembly App_Code");
|
||||
}
|
||||
if (e.InnerException is SecurityException == false)
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
|
||||
return assemblies;
|
||||
});
|
||||
}
|
||||
|
||||
//Lazy access to the all assemblies list
|
||||
private readonly Lazy<HashSet<Assembly>> _allAssemblies;
|
||||
private volatile HashSet<Assembly> _localFilteredAssemblyCache;
|
||||
private readonly object _localFilteredAssemblyCacheLocker = new object();
|
||||
private readonly List<string> _notifiedLoadExceptionAssemblies = new List<string>();
|
||||
private static readonly ConcurrentDictionary<string, Type> TypeNamesCache= new ConcurrentDictionary<string, Type>();
|
||||
private string _rootDir = "";
|
||||
private readonly string[] _assembliesAcceptingLoadExceptions;
|
||||
|
||||
// FIXME - this is only an interim change, once the IIOHelper stuff is merged we should use IIOHelper here
|
||||
private string GetRootDirectorySafe()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_rootDir) == false)
|
||||
{
|
||||
if (e.InnerException is SecurityException == false)
|
||||
throw;
|
||||
return _rootDir;
|
||||
}
|
||||
|
||||
return assemblies;
|
||||
});
|
||||
var codeBase = Assembly.GetExecutingAssembly().CodeBase;
|
||||
var uri = new Uri(codeBase);
|
||||
var path = uri.LocalPath;
|
||||
var baseDirectory = Path.GetDirectoryName(path);
|
||||
if (string.IsNullOrEmpty(baseDirectory))
|
||||
throw new PanicException("No root directory could be resolved.");
|
||||
|
||||
_rootDir = baseDirectory.Contains("bin")
|
||||
? baseDirectory.Substring(0, baseDirectory.LastIndexOf("bin", StringComparison.OrdinalIgnoreCase) - 1)
|
||||
: baseDirectory;
|
||||
|
||||
return _rootDir;
|
||||
}
|
||||
|
||||
private bool AcceptsLoadExceptions(Assembly a)
|
||||
{
|
||||
if (_assembliesAcceptingLoadExceptions.Length == 0)
|
||||
return false;
|
||||
if (_assembliesAcceptingLoadExceptions.Length == 1 && _assembliesAcceptingLoadExceptions[0] == "*")
|
||||
return true;
|
||||
var name = a.GetName().Name; // simple name of the assembly
|
||||
return _assembliesAcceptingLoadExceptions.Any(pattern =>
|
||||
{
|
||||
if (pattern.Length > name.Length) return false; // pattern longer than name
|
||||
if (pattern.Length == name.Length) return pattern.InvariantEquals(name); // same length, must be identical
|
||||
if (pattern[pattern.Length] != '.') return false; // pattern is shorter than name, must end with dot
|
||||
return name.StartsWith(pattern); // and name must start with pattern
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a list of found local Assemblies excluding the known assemblies we don't want to scan
|
||||
/// and excluding the ones passed in and excluding the exclusion list filter, the results of this are
|
||||
/// cached for performance reasons.
|
||||
/// lazily load a reference to all assemblies and only local assemblies.
|
||||
/// 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>
|
||||
/// <param name="excludeFromResults"></param>
|
||||
/// <returns></returns>
|
||||
internal static HashSet<Assembly> GetAssembliesWithKnownExclusions(
|
||||
IEnumerable<Assembly> excludeFromResults = null)
|
||||
/// <remarks>
|
||||
/// 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
|
||||
/// http://stackoverflow.com/questions/3552223/asp-net-appdomain-currentdomain-getassemblies-assemblies-missing-after-app
|
||||
/// http://stackoverflow.com/questions/2477787/difference-between-appdomain-getassemblies-and-buildmanager-getreferencedassembl
|
||||
/// </remarks>
|
||||
private IEnumerable<Assembly> GetAllAssemblies()
|
||||
{
|
||||
lock (LocalFilteredAssemblyCacheLocker)
|
||||
{
|
||||
if (_localFilteredAssemblyCache != null)
|
||||
return _localFilteredAssemblyCache;
|
||||
return _allAssemblies.Value;
|
||||
}
|
||||
|
||||
var assemblies = GetFilteredAssemblies(excludeFromResults, KnownAssemblyExclusionFilter);
|
||||
_localFilteredAssemblyCache = new HashSet<Assembly>(assemblies);
|
||||
return _localFilteredAssemblyCache;
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<Assembly> AssembliesToScan
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_localFilteredAssemblyCacheLocker)
|
||||
{
|
||||
if (_localFilteredAssemblyCache != null)
|
||||
return _localFilteredAssemblyCache;
|
||||
|
||||
var assemblies = GetFilteredAssemblies(null, KnownAssemblyExclusionFilter);
|
||||
_localFilteredAssemblyCache = new HashSet<Assembly>(assemblies);
|
||||
return _localFilteredAssemblyCache;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +159,7 @@ namespace Umbraco.Core.Composing
|
||||
/// <param name="excludeFromResults"></param>
|
||||
/// <param name="exclusionFilter"></param>
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<Assembly> GetFilteredAssemblies(
|
||||
private IEnumerable<Assembly> GetFilteredAssemblies(
|
||||
IEnumerable<Assembly> excludeFromResults = null,
|
||||
string[] exclusionFilter = null)
|
||||
{
|
||||
@@ -210,7 +181,7 @@ namespace Umbraco.Core.Composing
|
||||
/// NOTE the comma vs period... comma delimits the name in an Assembly FullName property so if it ends with comma then its an exact name match
|
||||
/// NOTE this means that "foo." will NOT exclude "foo.dll" but only "foo.*.dll"
|
||||
/// </remarks>
|
||||
internal static readonly string[] KnownAssemblyExclusionFilter = {
|
||||
private static readonly string[] KnownAssemblyExclusionFilter = {
|
||||
"Antlr3.",
|
||||
"AutoMapper,",
|
||||
"AutoMapper.",
|
||||
@@ -261,115 +232,40 @@ namespace Umbraco.Core.Composing
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Finds any classes derived from the type T that contain the attribute TAttribute
|
||||
/// Finds any classes derived from the assignTypeFrom Type that contain the attribute TAttribute
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TAttribute"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>()
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return FindClassesOfTypeWithAttribute<T, TAttribute>(GetAssembliesWithKnownExclusions(), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds any classes derived from the type T that contain the attribute TAttribute
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TAttribute"></typeparam>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(IEnumerable<Assembly> assemblies)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return FindClassesOfTypeWithAttribute<T, TAttribute>(assemblies, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds any classes derived from the type T that contain the attribute TAttribute
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TAttribute"></typeparam>
|
||||
/// <param name="assignTypeFrom"></param>
|
||||
/// <param name="attributeType"></param>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses)
|
||||
where TAttribute : Attribute
|
||||
public IEnumerable<Type> FindClassesOfTypeWithAttribute(
|
||||
Type assignTypeFrom,
|
||||
Type attributeType,
|
||||
IEnumerable<Assembly> assemblies = null,
|
||||
bool onlyConcreteClasses = true)
|
||||
{
|
||||
return FindClassesOfTypeWithAttribute<TAttribute>(typeof(T), assemblies, onlyConcreteClasses);
|
||||
var assemblyList = (assemblies ?? AssembliesToScan).ToList();
|
||||
|
||||
return GetClassesWithBaseType(assignTypeFrom, assemblyList, onlyConcreteClasses,
|
||||
//the additional filter will ensure that any found types also have the attribute applied.
|
||||
t => t.GetCustomAttributes(attributeType, false).Any());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds any classes derived from the assignTypeFrom Type that contain the attribute TAttribute
|
||||
/// Returns all types found of in the assemblies specified of type T
|
||||
/// </summary>
|
||||
/// <typeparam name="TAttribute"></typeparam>
|
||||
/// <param name="assignTypeFrom"></param>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<TAttribute>(
|
||||
Type assignTypeFrom,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses)
|
||||
where TAttribute : Attribute
|
||||
public IEnumerable<Type> FindClassesOfType(Type assignTypeFrom, IEnumerable<Assembly> assemblies = null, bool onlyConcreteClasses = true)
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException(nameof(assemblies));
|
||||
var assemblyList = (assemblies ?? AssembliesToScan).ToList();
|
||||
|
||||
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());
|
||||
return GetClassesWithBaseType(assignTypeFrom, assemblyList, onlyConcreteClasses);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches all filtered local assemblies specified for classes of the type passed in.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>()
|
||||
{
|
||||
return FindClassesOfType<T>(GetAssembliesWithKnownExclusions(), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all types found of in the assemblies specified of type T
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException(nameof(assemblies));
|
||||
|
||||
return GetClassesWithBaseType(typeof(T), assemblies, onlyConcreteClasses);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all types found of in the assemblies specified of type T
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>(IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
return FindClassesOfType<T>(assemblies, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <param name="onlyConcreteClasses">if set to <c>true</c> only concrete classes.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
|
||||
where T : Attribute
|
||||
{
|
||||
return FindClassesWithAttribute(typeof(T), assemblies, onlyConcreteClasses);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Finds any classes with the attribute.
|
||||
/// </summary>
|
||||
@@ -377,40 +273,58 @@ namespace Umbraco.Core.Composing
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <param name="onlyConcreteClasses">if set to <c>true</c> only concrete classes.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute(
|
||||
public IEnumerable<Type> FindClassesWithAttribute(
|
||||
Type attributeType,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses)
|
||||
IEnumerable<Assembly> assemblies = null,
|
||||
bool onlyConcreteClasses = true)
|
||||
{
|
||||
return GetClassesWithAttribute(attributeType, assemblies, onlyConcreteClasses);
|
||||
var assemblyList = (assemblies ?? AssembliesToScan).ToList();
|
||||
|
||||
return GetClassesWithAttribute(attributeType, assemblyList, onlyConcreteClasses);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute.
|
||||
/// Returns a Type for the string type name
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>(IEnumerable<Assembly> assemblies)
|
||||
where T : Attribute
|
||||
public virtual Type GetTypeByName(string name)
|
||||
{
|
||||
return FindClassesWithAttribute<T>(assemblies, true);
|
||||
}
|
||||
// This is exactly what the BuildManager does, if the type is an assembly qualified type
|
||||
// name it will find it.
|
||||
if (TypeNameContainsAssembly(name))
|
||||
{
|
||||
return Type.GetType(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute in filtered local assemblies
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>()
|
||||
where T : Attribute
|
||||
{
|
||||
return FindClassesWithAttribute<T>(GetAssembliesWithKnownExclusions());
|
||||
// It didn't parse, so try loading from each already loaded assembly and cache it
|
||||
return TypeNamesCache.GetOrAdd(name, s =>
|
||||
AppDomain.CurrentDomain.GetAssemblies()
|
||||
.Select(x => x.GetType(s))
|
||||
.FirstOrDefault(x => x != null));
|
||||
}
|
||||
|
||||
#region Private methods
|
||||
|
||||
private static IEnumerable<Type> GetClassesWithAttribute(
|
||||
// borrowed from aspnet System.Web.UI.Util
|
||||
private static bool TypeNameContainsAssembly(string typeName)
|
||||
{
|
||||
return CommaIndexInTypeName(typeName) > 0;
|
||||
}
|
||||
|
||||
// borrowed from aspnet System.Web.UI.Util
|
||||
private static int CommaIndexInTypeName(string typeName)
|
||||
{
|
||||
var num1 = typeName.LastIndexOf(',');
|
||||
if (num1 < 0)
|
||||
return -1;
|
||||
var num2 = typeName.LastIndexOf(']');
|
||||
if (num2 > num1)
|
||||
return -1;
|
||||
return typeName.IndexOf(',', num2 + 1);
|
||||
}
|
||||
|
||||
private IEnumerable<Type> GetClassesWithAttribute(
|
||||
Type attributeType,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses)
|
||||
@@ -441,7 +355,7 @@ namespace Umbraco.Core.Composing
|
||||
}
|
||||
catch (TypeLoadException ex)
|
||||
{
|
||||
Current.Logger.Error(typeof(TypeFinder), ex, "Could not query types on {Assembly} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", assembly);
|
||||
_logger.Error(typeof(TypeFinder), ex, "Could not query types on {Assembly} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", assembly);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -477,7 +391,7 @@ namespace Umbraco.Core.Composing
|
||||
/// <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> GetClassesWithBaseType(
|
||||
private IEnumerable<Type> GetClassesWithBaseType(
|
||||
Type baseType,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses,
|
||||
@@ -507,7 +421,7 @@ namespace Umbraco.Core.Composing
|
||||
}
|
||||
catch (TypeLoadException ex)
|
||||
{
|
||||
Current.Logger.Error(typeof(TypeFinder), ex, "Could not query types on {Assembly} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", assembly);
|
||||
_logger.Error(typeof(TypeFinder), ex, "Could not query types on {Assembly} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", assembly);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -533,7 +447,7 @@ namespace Umbraco.Core.Composing
|
||||
return types;
|
||||
}
|
||||
|
||||
internal static IEnumerable<Type> GetTypesWithFormattedException(Assembly a)
|
||||
private IEnumerable<Type> GetTypesWithFormattedException(Assembly a)
|
||||
{
|
||||
//if the assembly is dynamic, do not try to scan it
|
||||
if (a.IsDynamic)
|
||||
@@ -569,12 +483,12 @@ namespace Umbraco.Core.Composing
|
||||
if (AcceptsLoadExceptions(a) == false) throw ex;
|
||||
|
||||
// log a warning, and return what we can
|
||||
lock (NotifiedLoadExceptionAssemblies)
|
||||
lock (_notifiedLoadExceptionAssemblies)
|
||||
{
|
||||
if (NotifiedLoadExceptionAssemblies.Contains(a.FullName) == false)
|
||||
if (_notifiedLoadExceptionAssemblies.Contains(a.FullName) == false)
|
||||
{
|
||||
NotifiedLoadExceptionAssemblies.Add(a.FullName);
|
||||
Current.Logger.Warn(typeof (TypeFinder), ex, "Could not load all types from {TypeName}.", a.GetName().Name);
|
||||
_notifiedLoadExceptionAssemblies.Add(a.FullName);
|
||||
_logger.Warn(typeof (TypeFinder), ex, "Could not load all types from {TypeName}.", a.GetName().Name);
|
||||
}
|
||||
}
|
||||
return rex.Types.WhereNotNull().ToArray();
|
||||
@@ -595,8 +509,7 @@ namespace Umbraco.Core.Composing
|
||||
sb.Append(". ");
|
||||
sb.Append(loaderException.GetType().FullName);
|
||||
|
||||
var tloadex = loaderException as TypeLoadException;
|
||||
if (tloadex != null)
|
||||
if (loaderException is TypeLoadException tloadex)
|
||||
{
|
||||
sb.Append(" on ");
|
||||
sb.Append(tloadex.TypeName);
|
||||
@@ -609,24 +522,6 @@ namespace Umbraco.Core.Composing
|
||||
|
||||
#endregion
|
||||
|
||||
public static Type GetTypeByName(string typeName)
|
||||
{
|
||||
var type = BuildManager.GetType(typeName, false);
|
||||
if (type != null) return type;
|
||||
|
||||
// TODO: This isn't very elegant, and will have issues since the AppDomain.CurrentDomain
|
||||
// doesn't actualy load in all assemblies, only the types that have been referenced so far.
|
||||
// However, in a web context, the BuildManager will have executed which will force all assemblies
|
||||
// to be loaded so it's fine for now.
|
||||
// It could be fairly easy to parse the typeName to get the assembly name and then do Assembly.Load and
|
||||
// find the type from there.
|
||||
|
||||
//now try fall back procedures.
|
||||
type = Type.GetType(typeName);
|
||||
if (type != null) return type;
|
||||
return AppDomain.CurrentDomain.GetAssemblies()
|
||||
.Select(x => x.GetType(typeName))
|
||||
.FirstOrDefault(x => x != null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
public static class TypeFinderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Finds any classes derived from the type T that contain the attribute TAttribute
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TAttribute"></typeparam>
|
||||
/// <param name="typeFinder"></param>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(this ITypeFinder typeFinder, IEnumerable<Assembly> assemblies = null, bool onlyConcreteClasses = true)
|
||||
where TAttribute : Attribute
|
||||
=> typeFinder.FindClassesOfTypeWithAttribute(typeof(T), typeof(TAttribute), assemblies, onlyConcreteClasses);
|
||||
|
||||
/// <summary>
|
||||
/// Returns all types found of in the assemblies specified of type T
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="typeFinder"></param>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>(this ITypeFinder typeFinder, IEnumerable<Assembly> assemblies = null, bool onlyConcreteClasses = true)
|
||||
=> typeFinder.FindClassesOfType(typeof(T), assemblies, onlyConcreteClasses);
|
||||
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="typeFinder"></param>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <param name="onlyConcreteClasses">if set to <c>true</c> only concrete classes.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>(this ITypeFinder typeFinder, IEnumerable<Assembly> assemblies = null, bool onlyConcreteClasses = true)
|
||||
where T : Attribute
|
||||
=> typeFinder.FindClassesWithAttribute(typeof(T), assemblies, onlyConcreteClasses);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ using System.Reflection;
|
||||
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// A utility class for type checking, this provides internal caching so that calls to these methods will be faster
|
||||
/// than doing a manual type check in c#
|
||||
@@ -18,9 +19,11 @@ namespace Umbraco.Core.Composing
|
||||
= 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>
|
||||
/// Based on a type we'll check if it is IEnumerable{T} (or similar) and if so we'll return a List{T}, this will also deal with array types and return List{T} for those too.
|
||||
/// If it cannot be done, null is returned.
|
||||
|
||||
+43
-40
@@ -5,30 +5,30 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using System.Web.Compilation;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Collections;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using File = System.IO.File;
|
||||
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Provides methods to find and instantiate types.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>This class should be used to get all types, the <see cref="TypeFinder"/> class should never be used directly.</para>
|
||||
/// <para>This class should be used to get all types, the <see cref="ITypeFinder"/> class should never be used directly.</para>
|
||||
/// <para>In most cases this class is not used directly but through extension methods that retrieve specific types.</para>
|
||||
/// <para>This class caches the types it knows to avoid excessive assembly scanning and shorten startup times, relying
|
||||
/// on a hash of the DLLs in the ~/bin folder to check for cache expiration.</para>
|
||||
/// </remarks>
|
||||
public class TypeLoader
|
||||
public sealed class TypeLoader
|
||||
{
|
||||
private const string CacheKey = "umbraco-types.list";
|
||||
|
||||
private readonly IIOHelper _ioHelper;
|
||||
private readonly IAppPolicyCache _runtimeCache;
|
||||
private readonly IProfilingLogger _logger;
|
||||
|
||||
@@ -42,31 +42,40 @@ namespace Umbraco.Core.Composing
|
||||
private string _currentAssembliesHash;
|
||||
private IEnumerable<Assembly> _assemblies;
|
||||
private bool _reportedChange;
|
||||
private readonly string _localTempPath;
|
||||
private readonly DirectoryInfo _localTempPath;
|
||||
private string _fileBasePath;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TypeLoader"/> class.
|
||||
/// </summary>
|
||||
/// <param name="ioHelper"></param>
|
||||
/// <param name="typeFinder"></param>
|
||||
/// <param name="runtimeCache">The application runtime cache.</param>
|
||||
/// <param name="localTempPath">Files storage location.</param>
|
||||
/// <param name="logger">A profiling logger.</param>
|
||||
public TypeLoader(IAppPolicyCache runtimeCache, string localTempPath, IProfilingLogger logger)
|
||||
: this(runtimeCache, localTempPath, logger, true)
|
||||
/// <param name="assembliesToScan"></param>
|
||||
public TypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, DirectoryInfo localTempPath, IProfilingLogger logger, IEnumerable<Assembly> assembliesToScan = null)
|
||||
: this(ioHelper, typeFinder, runtimeCache, localTempPath, logger, true, assembliesToScan)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TypeLoader"/> class.
|
||||
/// </summary>
|
||||
/// <param name="ioHelper"></param>
|
||||
/// <param name="typeFinder"></param>
|
||||
/// <param name="runtimeCache">The application runtime cache.</param>
|
||||
/// <param name="localTempPath">Files storage location.</param>
|
||||
/// <param name="logger">A profiling logger.</param>
|
||||
/// <param name="detectChanges">Whether to detect changes using hashes.</param>
|
||||
internal TypeLoader(IAppPolicyCache runtimeCache, string localTempPath, IProfilingLogger logger, bool detectChanges)
|
||||
/// <param name="assembliesToScan"></param>
|
||||
public TypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, DirectoryInfo localTempPath, IProfilingLogger logger, bool detectChanges, IEnumerable<Assembly> assembliesToScan = null)
|
||||
{
|
||||
TypeFinder = typeFinder ?? throw new ArgumentNullException(nameof(typeFinder));
|
||||
_ioHelper = ioHelper;
|
||||
_runtimeCache = runtimeCache ?? throw new ArgumentNullException(nameof(runtimeCache));
|
||||
_localTempPath = localTempPath;
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_assemblies = assembliesToScan;
|
||||
|
||||
if (detectChanges)
|
||||
{
|
||||
@@ -99,11 +108,10 @@ namespace Umbraco.Core.Composing
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new, test/blank, instance of the <see cref="TypeLoader"/> class.
|
||||
/// Returns the underlying <see cref="ITypeFinder"/>
|
||||
/// </summary>
|
||||
/// <remarks>The initialized instance cannot get types.</remarks>
|
||||
internal TypeLoader()
|
||||
{ }
|
||||
// ReSharper disable once MemberCanBePrivate.Global
|
||||
public ITypeFinder TypeFinder { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the set of assemblies to scan.
|
||||
@@ -115,25 +123,21 @@ namespace Umbraco.Core.Composing
|
||||
/// <para>This is for unit tests.</para>
|
||||
/// </remarks>
|
||||
// internal for tests
|
||||
internal IEnumerable<Assembly> AssembliesToScan
|
||||
{
|
||||
get => _assemblies ?? (_assemblies = TypeFinder.GetAssembliesWithKnownExclusions());
|
||||
set => _assemblies = value;
|
||||
}
|
||||
public IEnumerable<Assembly> AssembliesToScan => _assemblies ?? (_assemblies = TypeFinder.AssembliesToScan);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type lists.
|
||||
/// </summary>
|
||||
/// <remarks>For unit tests.</remarks>
|
||||
// internal for tests
|
||||
internal IEnumerable<TypeList> TypeLists => _types.Values;
|
||||
public IEnumerable<TypeList> TypeLists => _types.Values;
|
||||
|
||||
/// <summary>
|
||||
/// Sets a type list.
|
||||
/// </summary>
|
||||
/// <remarks>For unit tests.</remarks>
|
||||
// internal for tests
|
||||
internal void AddTypeList(TypeList typeList)
|
||||
public void AddTypeList(TypeList typeList)
|
||||
{
|
||||
var tobject = typeof(object); // CompositeTypeTypeKey does not support null values
|
||||
_types[new CompositeTypeTypeKey(typeList.BaseType ?? tobject, typeList.AttributeType ?? tobject)] = typeList;
|
||||
@@ -180,12 +184,16 @@ namespace Umbraco.Core.Composing
|
||||
|
||||
_currentAssembliesHash = GetFileHash(new List<Tuple<FileSystemInfo, bool>>
|
||||
{
|
||||
// TODO: Would be nicer to abstract this logic out into IAssemblyHash
|
||||
|
||||
// TODO: Use constants from SystemDirectories when we can (once it's ported to netstandard lib)
|
||||
|
||||
// the bin folder and everything in it
|
||||
new Tuple<FileSystemInfo, bool>(new DirectoryInfo(Current.IOHelper.MapPath(SystemDirectories.Bin)), false),
|
||||
new Tuple<FileSystemInfo, bool>(new DirectoryInfo(_ioHelper.MapPath("~/bin")), false),
|
||||
// the app code folder and everything in it
|
||||
new Tuple<FileSystemInfo, bool>(new DirectoryInfo(Current.IOHelper.MapPath("~/App_Code")), false),
|
||||
new Tuple<FileSystemInfo, bool>(new DirectoryInfo(_ioHelper.MapPath("~/App_Code")), false),
|
||||
// global.asax (the app domain also monitors this, if it changes will do a full restart)
|
||||
new Tuple<FileSystemInfo, bool>(new FileInfo(Current.IOHelper.MapPath("~/global.asax")), false)
|
||||
new Tuple<FileSystemInfo, bool>(new FileInfo(_ioHelper.MapPath("~/global.asax")), false)
|
||||
}, _logger);
|
||||
|
||||
return _currentAssembliesHash;
|
||||
@@ -267,7 +275,7 @@ namespace Umbraco.Core.Composing
|
||||
/// <param name="logger">A profiling logger.</param>
|
||||
/// <returns>The hash.</returns>
|
||||
// internal for tests
|
||||
internal static string GetFileHash(IEnumerable<FileSystemInfo> filesAndFolders, IProfilingLogger logger)
|
||||
public static string GetFileHash(IEnumerable<FileSystemInfo> filesAndFolders, IProfilingLogger logger)
|
||||
{
|
||||
using (logger.DebugDuration<TypeLoader>("Determining hash of code files on disk", "Hash determined"))
|
||||
{
|
||||
@@ -298,7 +306,7 @@ namespace Umbraco.Core.Composing
|
||||
private const int FileDeleteTimeout = 4000; // milliseconds
|
||||
|
||||
// internal for tests
|
||||
internal Attempt<IEnumerable<string>> TryGetCached(Type baseType, Type attributeType)
|
||||
public Attempt<IEnumerable<string>> TryGetCached(Type baseType, Type attributeType)
|
||||
{
|
||||
var cache = _runtimeCache.GetCacheItem<Dictionary<Tuple<string, string>, IEnumerable<string>>>(CacheKey, ReadCacheSafe, TimeSpan.FromSeconds(ListFileCacheDuration));
|
||||
|
||||
@@ -331,7 +339,7 @@ namespace Umbraco.Core.Composing
|
||||
}
|
||||
|
||||
// internal for tests
|
||||
internal Dictionary<Tuple<string, string>, IEnumerable<string>> ReadCache()
|
||||
public Dictionary<Tuple<string, string>, IEnumerable<string>> ReadCache()
|
||||
{
|
||||
var cache = new Dictionary<Tuple<string, string>, IEnumerable<string>>();
|
||||
|
||||
@@ -377,7 +385,7 @@ namespace Umbraco.Core.Composing
|
||||
}
|
||||
|
||||
// internal for tests
|
||||
internal string GetTypesListFilePath() => GetFileBasePath() + ".list";
|
||||
public string GetTypesListFilePath() => GetFileBasePath() + ".list";
|
||||
|
||||
private string GetTypesHashFilePath() => GetFileBasePath() + ".hash";
|
||||
|
||||
@@ -388,7 +396,7 @@ namespace Umbraco.Core.Composing
|
||||
if (_fileBasePath != null)
|
||||
return _fileBasePath;
|
||||
|
||||
_fileBasePath = Path.Combine(_localTempPath, "TypesCache", "umbraco-types." + NetworkHelper.FileSafeMachineName);
|
||||
_fileBasePath = Path.Combine(_localTempPath.FullName, "TypesCache", "umbraco-types." + NetworkHelper.FileSafeMachineName);
|
||||
|
||||
// ensure that the folder exists
|
||||
var directory = Path.GetDirectoryName(_fileBasePath);
|
||||
@@ -402,7 +410,7 @@ namespace Umbraco.Core.Composing
|
||||
}
|
||||
|
||||
// internal for tests
|
||||
internal void WriteCache()
|
||||
public void WriteCache()
|
||||
{
|
||||
_logger.Debug<TypeLoader>("Writing cache file.");
|
||||
var typesListFilePath = GetTypesListFilePath();
|
||||
@@ -720,18 +728,13 @@ namespace Umbraco.Core.Composing
|
||||
// successfully retrieved types from the file cache: load
|
||||
foreach (var type in cacheResult.Result)
|
||||
{
|
||||
try
|
||||
{
|
||||
// we use the build manager to ensure we get all types loaded, this is slightly slower than
|
||||
// Type.GetType but if the types in the assembly aren't loaded yet it would fail whereas
|
||||
// BuildManager will load them - this is how eg MVC loads types, etc - no need to make it
|
||||
// more complicated
|
||||
typeList.Add(BuildManager.GetType(type, true));
|
||||
}
|
||||
catch (Exception ex)
|
||||
var resolvedType = TypeFinder.GetTypeByName(type);
|
||||
if (resolvedType != null)
|
||||
typeList.Add(resolvedType);
|
||||
else
|
||||
{
|
||||
// in case of any exception, we have to exit, and revert to scanning
|
||||
_logger.Error<TypeLoader>(ex, "Getting {TypeName}: failed to load cache file type {CacheType}, reverting to scanning assemblies.", GetName(baseType, attributeType), type);
|
||||
_logger.Warn<TypeLoader>("Getting {TypeName}: failed to load cache file type {CacheType}, reverting to scanning assemblies.", GetName(baseType, attributeType), type);
|
||||
scan = true;
|
||||
break;
|
||||
}
|
||||
@@ -783,7 +786,7 @@ namespace Umbraco.Core.Composing
|
||||
/// Represents a list of types obtained by looking for types inheriting/implementing a
|
||||
/// specified type, and/or marked with a specified attribute type.
|
||||
/// </summary>
|
||||
internal class TypeList
|
||||
public sealed class TypeList
|
||||
{
|
||||
private readonly HashSet<Type> _types = new HashSet<Type>();
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
public interface ITypeFinderConfig
|
||||
{
|
||||
IEnumerable<string> AssembliesAcceptingLoadExceptions { get; }
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ namespace Umbraco.Core
|
||||
IUmbracoDatabaseFactory databaseFactory,
|
||||
TypeLoader typeLoader,
|
||||
IRuntimeState state,
|
||||
ITypeFinder typeFinder,
|
||||
IIOHelper ioHelper)
|
||||
{
|
||||
composition.RegisterUnique(logger);
|
||||
@@ -32,6 +33,7 @@ namespace Umbraco.Core
|
||||
composition.RegisterUnique(factory => factory.GetInstance<IUmbracoDatabaseFactory>().SqlContext);
|
||||
composition.RegisterUnique(typeLoader);
|
||||
composition.RegisterUnique(state);
|
||||
composition.RegisterUnique(typeFinder);
|
||||
composition.RegisterUnique(ioHelper);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace Umbraco.Core.IO
|
||||
{
|
||||
public class IOHelper : IIOHelper
|
||||
{
|
||||
internal static IIOHelper Default { get; } = new IOHelper();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value forcing Umbraco to consider it is non-hosted.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Web;
|
||||
using System.Web.Hosting;
|
||||
using Umbraco.Core.Cache;
|
||||
@@ -42,6 +43,11 @@ namespace Umbraco.Core.Runtime
|
||||
/// </summary>
|
||||
protected IProfilingLogger ProfilingLogger { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="ITypeFinder"/>
|
||||
/// </summary>
|
||||
protected ITypeFinder TypeFinder { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IIOHelper"/>
|
||||
/// </summary>
|
||||
@@ -58,13 +64,22 @@ namespace Umbraco.Core.Runtime
|
||||
|
||||
// loggers
|
||||
var logger = Logger = GetLogger();
|
||||
if (logger == null)
|
||||
throw new InvalidOperationException($"The object returned from {nameof(GetLogger)} cannot be null");
|
||||
var profiler = Profiler = GetProfiler();
|
||||
if (profiler == null)
|
||||
throw new InvalidOperationException($"The object returned from {nameof(GetProfiler)} cannot be null");
|
||||
|
||||
var profilingLogger = ProfilingLogger = new ProfilingLogger(logger, profiler);
|
||||
|
||||
IOHelper = GetIOHelper();
|
||||
if (IOHelper == null)
|
||||
throw new InvalidOperationException($"The object returned from {nameof(GetIOHelper)} cannot be null");
|
||||
|
||||
TypeFinder = GetTypeFinder();
|
||||
if (TypeFinder == null)
|
||||
throw new InvalidOperationException($"The object returned from {nameof(GetTypeFinder)} cannot be null");
|
||||
|
||||
// the boot loader boots using a container scope, so anything that is PerScope will
|
||||
// be disposed after the boot loader has booted, and anything else will remain.
|
||||
// note that this REQUIRES that perWebRequestScope has NOT been enabled yet, else
|
||||
@@ -120,8 +135,8 @@ namespace Umbraco.Core.Runtime
|
||||
// configs
|
||||
var configs = GetConfigs();
|
||||
|
||||
// type loader
|
||||
var typeLoader = new TypeLoader(appCaches.RuntimeCache, configs.Global().LocalTempPath, ProfilingLogger);
|
||||
// type finder/loader
|
||||
var typeLoader = new TypeLoader(IOHelper, TypeFinder, appCaches.RuntimeCache, new DirectoryInfo(configs.Global().LocalTempPath), ProfilingLogger);
|
||||
|
||||
// runtime state
|
||||
// beware! must use '() => _factory.GetInstance<T>()' and NOT '_factory.GetInstance<T>'
|
||||
@@ -137,9 +152,9 @@ namespace Umbraco.Core.Runtime
|
||||
// main dom
|
||||
var mainDom = new MainDom(Logger);
|
||||
|
||||
// create the composition
|
||||
// create the composition
|
||||
composition = new Composition(register, typeLoader, ProfilingLogger, _state, configs);
|
||||
composition.RegisterEssentials(Logger, Profiler, ProfilingLogger, mainDom, appCaches, databaseFactory, typeLoader, _state, IOHelper);
|
||||
composition.RegisterEssentials(Logger, Profiler, ProfilingLogger, mainDom, appCaches, databaseFactory, typeLoader, _state, TypeFinder, IOHelper);
|
||||
|
||||
// run handlers
|
||||
RuntimeOptions.DoRuntimeEssentials(composition, appCaches, typeLoader, databaseFactory);
|
||||
@@ -297,7 +312,6 @@ namespace Umbraco.Core.Runtime
|
||||
/// </summary>
|
||||
public virtual void Compose(Composition composition)
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
|
||||
#region Getters
|
||||
@@ -322,12 +336,19 @@ namespace Umbraco.Core.Runtime
|
||||
protected virtual IProfiler GetProfiler()
|
||||
=> new LogProfiler(Logger);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ITypeFinder"/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected virtual ITypeFinder GetTypeFinder()
|
||||
=> new TypeFinder(Logger);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="IIOHelper"/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected virtual IIOHelper GetIOHelper()
|
||||
=> new Umbraco.Core.IO.IOHelper();
|
||||
=> Umbraco.Core.IO.IOHelper.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the application caches.
|
||||
@@ -339,9 +360,9 @@ namespace Umbraco.Core.Runtime
|
||||
// is overridden by the web runtime
|
||||
|
||||
return new AppCaches(
|
||||
new DeepCloneAppCache(new ObjectCacheAppCache()),
|
||||
new DeepCloneAppCache(new ObjectCacheAppCache(TypeFinder)),
|
||||
NoAppCache.Instance,
|
||||
new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache())));
|
||||
new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache(TypeFinder))));
|
||||
}
|
||||
|
||||
// by default, returns null, meaning that Umbraco should auto-detect the application root path.
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace Umbraco.Core.Scoping
|
||||
{
|
||||
private readonly ScopeProvider _scopeProvider;
|
||||
private readonly ILogger _logger;
|
||||
private readonly ITypeFinder _typeFinder;
|
||||
|
||||
private readonly IsolationLevel _isolationLevel;
|
||||
private readonly RepositoryCacheMode _repositoryCacheMode;
|
||||
@@ -35,7 +36,7 @@ namespace Umbraco.Core.Scoping
|
||||
|
||||
// initializes a new scope
|
||||
private Scope(ScopeProvider scopeProvider,
|
||||
ILogger logger, FileSystems fileSystems, Scope parent, ScopeContext scopeContext, bool detachable,
|
||||
ILogger logger, ITypeFinder typeFinder, FileSystems fileSystems, Scope parent, ScopeContext scopeContext, bool detachable,
|
||||
IsolationLevel isolationLevel = IsolationLevel.Unspecified,
|
||||
RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified,
|
||||
IEventDispatcher eventDispatcher = null,
|
||||
@@ -45,6 +46,7 @@ namespace Umbraco.Core.Scoping
|
||||
{
|
||||
_scopeProvider = scopeProvider;
|
||||
_logger = logger;
|
||||
_typeFinder = typeFinder;
|
||||
|
||||
Context = scopeContext;
|
||||
|
||||
@@ -109,26 +111,26 @@ namespace Umbraco.Core.Scoping
|
||||
|
||||
// initializes a new scope
|
||||
public Scope(ScopeProvider scopeProvider,
|
||||
ILogger logger, FileSystems fileSystems, bool detachable, ScopeContext scopeContext,
|
||||
ILogger logger, ITypeFinder typeFinder, FileSystems fileSystems, bool detachable, ScopeContext scopeContext,
|
||||
IsolationLevel isolationLevel = IsolationLevel.Unspecified,
|
||||
RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified,
|
||||
IEventDispatcher eventDispatcher = null,
|
||||
bool? scopeFileSystems = null,
|
||||
bool callContext = false,
|
||||
bool autoComplete = false)
|
||||
: this(scopeProvider, logger, fileSystems, null, scopeContext, detachable, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete)
|
||||
: this(scopeProvider, logger, typeFinder, fileSystems, null, scopeContext, detachable, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete)
|
||||
{ }
|
||||
|
||||
// initializes a new scope in a nested scopes chain, with its parent
|
||||
public Scope(ScopeProvider scopeProvider,
|
||||
ILogger logger, FileSystems fileSystems, Scope parent,
|
||||
ILogger logger, ITypeFinder typeFinder, FileSystems fileSystems, Scope parent,
|
||||
IsolationLevel isolationLevel = IsolationLevel.Unspecified,
|
||||
RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified,
|
||||
IEventDispatcher eventDispatcher = null,
|
||||
bool? scopeFileSystems = null,
|
||||
bool callContext = false,
|
||||
bool autoComplete = false)
|
||||
: this(scopeProvider, logger, fileSystems, parent, null, false, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete)
|
||||
: this(scopeProvider, logger, typeFinder, fileSystems, parent, null, false, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete)
|
||||
{ }
|
||||
|
||||
public Guid InstanceId { get; } = Guid.NewGuid();
|
||||
@@ -175,7 +177,7 @@ namespace Umbraco.Core.Scoping
|
||||
if (ParentScope != null) return ParentScope.IsolatedCaches;
|
||||
|
||||
return _isolatedCaches ?? (_isolatedCaches
|
||||
= new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache())));
|
||||
= new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache(_typeFinder))));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,13 +22,15 @@ namespace Umbraco.Core.Scoping
|
||||
internal class ScopeProvider : IScopeProvider, IScopeAccessor
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly ITypeFinder _typeFinder;
|
||||
private readonly FileSystems _fileSystems;
|
||||
|
||||
public ScopeProvider(IUmbracoDatabaseFactory databaseFactory, FileSystems fileSystems, ILogger logger)
|
||||
public ScopeProvider(IUmbracoDatabaseFactory databaseFactory, FileSystems fileSystems, ILogger logger, ITypeFinder typeFinder)
|
||||
{
|
||||
DatabaseFactory = databaseFactory;
|
||||
_fileSystems = fileSystems;
|
||||
_logger = logger;
|
||||
_typeFinder = typeFinder;
|
||||
|
||||
// take control of the FileSystems
|
||||
_fileSystems.IsScoped = () => AmbientScope != null && AmbientScope.ScopedFileSystems;
|
||||
@@ -323,7 +325,7 @@ namespace Umbraco.Core.Scoping
|
||||
IEventDispatcher eventDispatcher = null,
|
||||
bool? scopeFileSystems = null)
|
||||
{
|
||||
return new Scope(this, _logger, _fileSystems, true, null, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems);
|
||||
return new Scope(this, _logger, _typeFinder, _fileSystems, true, null, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -379,13 +381,13 @@ namespace Umbraco.Core.Scoping
|
||||
{
|
||||
var ambientContext = AmbientContext;
|
||||
var newContext = ambientContext == null ? new ScopeContext() : null;
|
||||
var scope = new Scope(this, _logger, _fileSystems, false, newContext, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete);
|
||||
var scope = new Scope(this, _logger, _typeFinder, _fileSystems, false, newContext, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete);
|
||||
// assign only if scope creation did not throw!
|
||||
SetAmbient(scope, newContext ?? ambientContext);
|
||||
return scope;
|
||||
}
|
||||
|
||||
var nested = new Scope(this, _logger, _fileSystems, ambientScope, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete);
|
||||
var nested = new Scope(this, _logger, _typeFinder, _fileSystems, ambientScope, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete);
|
||||
SetAmbient(nested, AmbientContext);
|
||||
return nested;
|
||||
}
|
||||
|
||||
@@ -127,14 +127,8 @@
|
||||
</Compile>
|
||||
-->
|
||||
<Compile Include="Cache\DefaultRepositoryCachePolicy.cs" />
|
||||
<Compile Include="Cache\FastDictionaryAppCacheBase.cs" />
|
||||
<Compile Include="Cache\ObjectCacheAppCache.cs" />
|
||||
<Compile Include="Compose\AuditEventsComponent.cs" />
|
||||
<Compile Include="Cache\CacheRefresherCollectionBuilder.cs" />
|
||||
<Compile Include="Cache\FastDictionaryAppCache.cs" />
|
||||
<Compile Include="Cache\FullDataSetRepositoryCachePolicy.cs" />
|
||||
<Compile Include="Cache\HttpRequestAppCache.cs" />
|
||||
<Compile Include="Cache\WebCachingAppCache.cs" />
|
||||
<Compile Include="Cache\RepositoryCachePolicyBase.cs" />
|
||||
<Compile Include="Cache\SingleItemsOnlyRepositoryCachePolicy.cs" />
|
||||
<Compile Include="Compose\AuditEventsComposer.cs" />
|
||||
@@ -185,8 +179,6 @@
|
||||
<Compile Include="Composing\LightInject\LightInjectContainer.cs" />
|
||||
<Compile Include="Composing\LightInject\MixedLightInjectScopeManagerProvider.cs" />
|
||||
<Compile Include="Composing\TargetedServiceFactory.cs" />
|
||||
<Compile Include="Composing\TypeFinder.cs" />
|
||||
<Compile Include="Composing\TypeLoader.cs" />
|
||||
<Compile Include="IO\IMediaFileSystem.cs" />
|
||||
<Compile Include="IO\IMediaPathScheme.cs" />
|
||||
<Compile Include="IO\IOHelper.cs" />
|
||||
|
||||
@@ -17,6 +17,13 @@ namespace Umbraco.Examine
|
||||
/// </summary>
|
||||
public abstract class LuceneIndexCreator : IIndexCreator
|
||||
{
|
||||
private readonly ITypeFinder _typeFinder;
|
||||
|
||||
protected LuceneIndexCreator(ITypeFinder typeFinder)
|
||||
{
|
||||
_typeFinder = typeFinder;
|
||||
}
|
||||
|
||||
public abstract IEnumerable<IIndex> Create();
|
||||
|
||||
/// <summary>
|
||||
@@ -38,7 +45,7 @@ namespace Umbraco.Examine
|
||||
if (!configuredDirectoryFactory.IsNullOrWhiteSpace())
|
||||
{
|
||||
//this should be a fully qualified type
|
||||
var factoryType = TypeFinder.GetTypeByName(configuredDirectoryFactory);
|
||||
var factoryType = _typeFinder.GetTypeByName(configuredDirectoryFactory);
|
||||
if (factoryType == null) throw new NullReferenceException("No directory type found for value: " + configuredDirectoryFactory);
|
||||
var directoryFactory = (IDirectoryFactory)Activator.CreateInstance(factoryType);
|
||||
return directoryFactory.CreateDirectory(dirInfo);
|
||||
|
||||
@@ -2,13 +2,17 @@
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Web;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Collections;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Tests.Collections;
|
||||
using Umbraco.Web.Cache;
|
||||
|
||||
namespace Umbraco.Tests.Cache
|
||||
{
|
||||
@@ -22,7 +26,8 @@ namespace Umbraco.Tests.Cache
|
||||
public override void Setup()
|
||||
{
|
||||
base.Setup();
|
||||
_provider = new DeepCloneAppCache(new WebCachingAppCache(HttpRuntime.Cache));
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
_provider = new DeepCloneAppCache(new WebCachingAppCache(HttpRuntime.Cache, typeFinder));
|
||||
}
|
||||
|
||||
internal override IAppCache AppCache => _provider;
|
||||
|
||||
@@ -9,6 +9,7 @@ using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Sync;
|
||||
using Umbraco.Tests.Components;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
|
||||
namespace Umbraco.Tests.Cache.DistributedCache
|
||||
{
|
||||
@@ -25,7 +26,7 @@ namespace Umbraco.Tests.Cache.DistributedCache
|
||||
{
|
||||
var register = RegisterFactory.Create();
|
||||
|
||||
var composition = new Composition(register, new TypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
var composition = new Composition(register, TestHelper.GetMockedTypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
|
||||
composition.RegisterUnique<IServerRegistrar>(_ => new TestServerRegistrar());
|
||||
composition.RegisterUnique<IServerMessenger>(_ => new TestServerMessenger());
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
using NUnit.Framework;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
|
||||
namespace Umbraco.Tests.Cache
|
||||
@@ -13,8 +16,9 @@ namespace Umbraco.Tests.Cache
|
||||
public override void Setup()
|
||||
{
|
||||
base.Setup();
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
_ctx = new FakeHttpContextFactory("http://localhost/test");
|
||||
_appCache = new HttpRequestAppCache(_ctx.HttpContext);
|
||||
_appCache = new HttpRequestAppCache(() => _ctx.HttpContext.Items, typeFinder);
|
||||
}
|
||||
|
||||
internal override IAppCache AppCache
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Tests.Cache
|
||||
{
|
||||
@@ -20,7 +23,8 @@ namespace Umbraco.Tests.Cache
|
||||
public override void Setup()
|
||||
{
|
||||
base.Setup();
|
||||
_provider = new ObjectCacheAppCache();
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
_provider = new ObjectCacheAppCache(typeFinder);
|
||||
}
|
||||
|
||||
internal override IAppCache AppCache
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Web;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Web.Cache;
|
||||
|
||||
namespace Umbraco.Tests.Cache
|
||||
{
|
||||
@@ -16,7 +20,8 @@ namespace Umbraco.Tests.Cache
|
||||
public override void Setup()
|
||||
{
|
||||
base.Setup();
|
||||
_appCache = new WebCachingAppCache(HttpRuntime.Cache);
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
_appCache = new WebCachingAppCache(HttpRuntime.Cache, typeFinder);
|
||||
}
|
||||
|
||||
internal override IAppCache AppCache => _appCache;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
@@ -31,9 +32,10 @@ namespace Umbraco.Tests.Components
|
||||
var mock = new Mock<IFactory>();
|
||||
|
||||
var logger = Mock.Of<ILogger>();
|
||||
var typeFinder = new TypeFinder(logger);
|
||||
var f = new UmbracoDatabaseFactory(logger, new Lazy<IMapperCollection>(() => new MapperCollection(Enumerable.Empty<BaseMapper>())));
|
||||
var fs = new FileSystems(mock.Object, logger);
|
||||
var p = new ScopeProvider(f, fs, logger);
|
||||
var p = new ScopeProvider(f, fs, logger, typeFinder);
|
||||
|
||||
mock.Setup(x => x.GetInstance(typeof (ILogger))).Returns(logger);
|
||||
mock.Setup(x => x.GetInstance(typeof (IProfilingLogger))).Returns(new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>()));
|
||||
@@ -51,7 +53,8 @@ namespace Umbraco.Tests.Components
|
||||
|
||||
private static TypeLoader MockTypeLoader()
|
||||
{
|
||||
return new TypeLoader();
|
||||
var ioHelper = IOHelper.Default;
|
||||
return new TypeLoader(ioHelper, Mock.Of<ITypeFinder>(), Mock.Of<IAppPolicyCache>(), new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), Mock.Of<IProfilingLogger>());
|
||||
}
|
||||
|
||||
public static IRuntimeState MockRuntimeState(RuntimeLevel level)
|
||||
@@ -361,7 +364,9 @@ namespace Umbraco.Tests.Components
|
||||
[Test]
|
||||
public void AllComposers()
|
||||
{
|
||||
var typeLoader = new TypeLoader(AppCaches.Disabled.RuntimeCache, Current.IOHelper.MapPath("~/App_Data/TEMP"), Mock.Of<IProfilingLogger>());
|
||||
var ioHelper = IOHelper.Default;
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
var typeLoader = new TypeLoader(ioHelper, typeFinder, AppCaches.Disabled.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), Mock.Of<IProfilingLogger>());
|
||||
|
||||
var register = MockRegister();
|
||||
var composition = new Composition(register, typeLoader, Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Run));
|
||||
|
||||
@@ -7,6 +7,7 @@ using Umbraco.Core.Composing;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Tests.Components;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
|
||||
namespace Umbraco.Tests.Composing
|
||||
{
|
||||
@@ -21,7 +22,7 @@ namespace Umbraco.Tests.Composing
|
||||
Current.Reset();
|
||||
|
||||
var register = RegisterFactory.Create();
|
||||
_composition = new Composition(register, new TypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
_composition = new Composition(register, TestHelper.GetMockedTypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
@@ -22,10 +23,9 @@ namespace Umbraco.Tests.Composing
|
||||
{
|
||||
ProfilingLogger = new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>());
|
||||
|
||||
TypeLoader = new TypeLoader(NoAppCache.Instance, Current.IOHelper.MapPath("~/App_Data/TEMP"), ProfilingLogger, detectChanges: false)
|
||||
{
|
||||
AssembliesToScan = AssembliesToScan
|
||||
};
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
var ioHelper = IOHelper.Default;
|
||||
TypeLoader = new TypeLoader(ioHelper, typeFinder, NoAppCache.Instance, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), ProfilingLogger, false, AssembliesToScan);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
@@ -36,7 +37,9 @@ namespace Umbraco.Tests.Composing
|
||||
.Returns(() => factoryFactory?.Invoke(mockedFactory));
|
||||
|
||||
var logger = new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>());
|
||||
var typeLoader = new TypeLoader(Mock.Of<IAppPolicyCache>(), Current.IOHelper.MapPath("~/App_Data/TEMP"), logger);
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
var ioHelper = IOHelper.Default;
|
||||
var typeLoader = new TypeLoader(ioHelper, typeFinder, Mock.Of<IAppPolicyCache>(), new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), logger);
|
||||
var composition = new Composition(mockedRegister, typeLoader, logger, Mock.Of<IRuntimeState>());
|
||||
|
||||
// create the factory, ensure it is the mocked factory
|
||||
|
||||
@@ -9,6 +9,7 @@ using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Tests.Components;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
|
||||
namespace Umbraco.Tests.Composing
|
||||
{
|
||||
@@ -40,7 +41,7 @@ namespace Umbraco.Tests.Composing
|
||||
public void LazyCollectionBuilderHandlesTypes()
|
||||
{
|
||||
var container = CreateRegister();
|
||||
var composition = new Composition(container, new TypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
|
||||
composition.WithCollectionBuilder<TestCollectionBuilder>()
|
||||
.Add<TransientObject3>()
|
||||
@@ -66,7 +67,7 @@ namespace Umbraco.Tests.Composing
|
||||
public void LazyCollectionBuilderHandlesProducers()
|
||||
{
|
||||
var container = CreateRegister();
|
||||
var composition = new Composition(container, new TypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
|
||||
composition.WithCollectionBuilder<TestCollectionBuilder>()
|
||||
.Add(() => new[] { typeof(TransientObject3), typeof(TransientObject2) })
|
||||
@@ -91,7 +92,7 @@ namespace Umbraco.Tests.Composing
|
||||
public void LazyCollectionBuilderHandlesTypesAndProducers()
|
||||
{
|
||||
var container = CreateRegister();
|
||||
var composition = new Composition(container, new TypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
|
||||
composition.WithCollectionBuilder<TestCollectionBuilder>()
|
||||
.Add<TransientObject3>()
|
||||
@@ -117,7 +118,7 @@ namespace Umbraco.Tests.Composing
|
||||
public void LazyCollectionBuilderThrowsOnIllegalTypes()
|
||||
{
|
||||
var container = CreateRegister();
|
||||
var composition = new Composition(container, new TypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
|
||||
composition.WithCollectionBuilder<TestCollectionBuilder>()
|
||||
.Add<TransientObject3>()
|
||||
@@ -139,7 +140,7 @@ namespace Umbraco.Tests.Composing
|
||||
public void LazyCollectionBuilderCanExcludeTypes()
|
||||
{
|
||||
var container = CreateRegister();
|
||||
var composition = new Composition(container, new TypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
|
||||
composition.WithCollectionBuilder<TestCollectionBuilder>()
|
||||
.Add<TransientObject3>()
|
||||
|
||||
@@ -9,6 +9,7 @@ using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.PackageActions;
|
||||
using Umbraco.Tests.Components;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
|
||||
namespace Umbraco.Tests.Composing
|
||||
{
|
||||
@@ -20,7 +21,7 @@ namespace Umbraco.Tests.Composing
|
||||
{
|
||||
var container = RegisterFactory.Create();
|
||||
|
||||
var composition = new Composition(container, new TypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
|
||||
composition.WithCollectionBuilder<PackageActionCollectionBuilder>()
|
||||
.Add(() => TypeLoader.GetPackageActions());
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Text;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using System.Web.Compilation;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
@@ -56,39 +57,19 @@ namespace Umbraco.Tests.Composing
|
||||
[Test]
|
||||
public void Find_Class_Of_Type_With_Attribute()
|
||||
{
|
||||
|
||||
var typesFound = TypeFinder.FindClassesOfTypeWithAttribute<TestEditor, MyTestAttribute>(_assemblies);
|
||||
var typeFinder = new TypeFinder(GetTestProfilingLogger());
|
||||
var typesFound = typeFinder.FindClassesOfTypeWithAttribute<TestEditor, MyTestAttribute>(_assemblies);
|
||||
Assert.AreEqual(2, typesFound.Count());
|
||||
}
|
||||
|
||||
//[Test]
|
||||
//public void Find_Classes_Of_Type()
|
||||
//{
|
||||
// var typesFound = TypeFinder.FindClassesOfType<IApplicationEventHandler>(_assemblies);
|
||||
// var originalTypesFound = TypeFinderOriginal.FindClassesOfType<IApplicationEventHandler>(_assemblies);
|
||||
|
||||
// foreach (var type in typesFound)
|
||||
// Console.WriteLine(type);
|
||||
// Console.WriteLine();
|
||||
// foreach (var type in originalTypesFound)
|
||||
// Console.WriteLine(type);
|
||||
|
||||
// // 6 classes in _assemblies implement IApplicationEventHandler
|
||||
// Assert.AreEqual(6, typesFound.Count());
|
||||
|
||||
// // however,
|
||||
// // Umbraco.Core.Profiling.WebProfiler is internal and is not returned by TypeFinderOriginal,
|
||||
// // that's a known issue of the legacy type finder, so we have to tweak the count here.
|
||||
// Assert.AreEqual(5, originalTypesFound.Count());
|
||||
//}
|
||||
|
||||
[Test]
|
||||
public void Find_Classes_With_Attribute()
|
||||
{
|
||||
var typesFound = TypeFinder.FindClassesWithAttribute<TreeAttribute>(_assemblies);
|
||||
var typeFinder = new TypeFinder(GetTestProfilingLogger());
|
||||
var typesFound = typeFinder.FindClassesWithAttribute<TreeAttribute>(_assemblies);
|
||||
Assert.AreEqual(0, typesFound.Count()); // 0 classes in _assemblies are marked with [Tree]
|
||||
|
||||
typesFound = TypeFinder.FindClassesWithAttribute<TreeAttribute>(new[] { typeof (UmbracoContext).Assembly });
|
||||
typesFound = typeFinder.FindClassesWithAttribute<TreeAttribute>(new[] { typeof (UmbracoContext).Assembly });
|
||||
Assert.AreEqual(22, typesFound.Count()); // + classes in Umbraco.Web are marked with [Tree]
|
||||
}
|
||||
|
||||
@@ -122,447 +103,6 @@ namespace Umbraco.Tests.Composing
|
||||
|
||||
}
|
||||
|
||||
//USED FOR THE ABOVE TESTS
|
||||
// see this issue for details: http://issues.umbraco.org/issue/U4-1187
|
||||
internal static class TypeFinderOriginal
|
||||
{
|
||||
|
||||
private static readonly ConcurrentBag<Assembly> LocalFilteredAssemblyCache = new ConcurrentBag<Assembly>();
|
||||
private static readonly ReaderWriterLockSlim LocalFilteredAssemblyCacheLocker = new ReaderWriterLockSlim();
|
||||
private static ReadOnlyCollection<Assembly> _allAssemblies = null;
|
||||
private static ReadOnlyCollection<Assembly> _binFolderAssemblies = null;
|
||||
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
|
||||
|
||||
/// <summary>
|
||||
/// lazily load a reference to all assemblies and only local assemblies.
|
||||
/// 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
|
||||
/// loaded in the CLR, not all assemblies.
|
||||
/// See these threads:
|
||||
/// http://issues.umbraco.org/issue/U5-198
|
||||
/// http://stackoverflow.com/questions/3552223/asp-net-appdomain-currentdomain-getassemblies-assemblies-missing-after-app
|
||||
/// http://stackoverflow.com/questions/2477787/difference-between-appdomain-getassemblies-and-buildmanager-getreferencedassembl
|
||||
/// </remarks>
|
||||
internal static IEnumerable<Assembly> GetAllAssemblies()
|
||||
{
|
||||
if (_allAssemblies == null)
|
||||
{
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
List<Assembly> assemblies = null;
|
||||
try
|
||||
{
|
||||
var isHosted = HttpContext.Current != null;
|
||||
|
||||
try
|
||||
{
|
||||
if (isHosted)
|
||||
{
|
||||
assemblies = new List<Assembly>(BuildManager.GetReferencedAssemblies().Cast<Assembly>());
|
||||
}
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
if (!(e.InnerException is SecurityException))
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
if (assemblies == null)
|
||||
{
|
||||
//NOTE: we cannot use AppDomain.CurrentDomain.GetAssemblies() because this only returns assemblies that have
|
||||
// already been loaded in to the app domain, instead we will look directly into the bin folder and load each one.
|
||||
var binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory;
|
||||
var binAssemblyFiles = Directory.GetFiles(binFolder.FullName, "*.dll", SearchOption.TopDirectoryOnly).ToList();
|
||||
assemblies = new List<Assembly>();
|
||||
foreach (var a in binAssemblyFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
var assName = AssemblyName.GetAssemblyName(a);
|
||||
var ass = Assembly.Load(assName);
|
||||
assemblies.Add(ass);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e is SecurityException || e is BadImageFormatException)
|
||||
{
|
||||
//swallow these exceptions
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if for some reason they are still no assemblies, then use the AppDomain to load in already loaded assemblies.
|
||||
if (!assemblies.Any())
|
||||
{
|
||||
assemblies.AddRange(AppDomain.CurrentDomain.GetAssemblies().ToList());
|
||||
}
|
||||
|
||||
//here we are trying to get the App_Code assembly
|
||||
var fileExtensions = new[] { ".cs", ".vb" }; //only vb and cs files are supported
|
||||
var appCodeFolder = new DirectoryInfo(Current.IOHelper.MapPath(Current.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())))
|
||||
{
|
||||
var appCodeAssembly = Assembly.Load("App_Code");
|
||||
if (!assemblies.Contains(appCodeAssembly)) // BuildManager will find App_Code already
|
||||
assemblies.Add(appCodeAssembly);
|
||||
}
|
||||
|
||||
//now set the _allAssemblies
|
||||
_allAssemblies = new ReadOnlyCollection<Assembly>(assemblies);
|
||||
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
if (!(e.InnerException is SecurityException))
|
||||
throw;
|
||||
|
||||
_binFolderAssemblies = _allAssemblies;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _allAssemblies;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns only assemblies found in the bin folder that have been loaded into the app domain.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This will be used if we implement App_Plugins from Umbraco v5 but currently it is not used.
|
||||
/// </remarks>
|
||||
internal static IEnumerable<Assembly> GetBinAssemblies()
|
||||
{
|
||||
|
||||
if (_binFolderAssemblies == null)
|
||||
{
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
var assemblies = GetAssembliesWithKnownExclusions().ToArray();
|
||||
var binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory;
|
||||
var binAssemblyFiles = Directory.GetFiles(binFolder.FullName, "*.dll", SearchOption.TopDirectoryOnly).ToList();
|
||||
var domainAssemblyNames = binAssemblyFiles.Select(AssemblyName.GetAssemblyName);
|
||||
var safeDomainAssemblies = new List<Assembly>();
|
||||
var binFolderAssemblies = new List<Assembly>();
|
||||
|
||||
foreach (var a in assemblies)
|
||||
{
|
||||
try
|
||||
{
|
||||
//do a test to see if its queryable in med trust
|
||||
var assemblyFile = a.GetAssemblyFile();
|
||||
safeDomainAssemblies.Add(a);
|
||||
}
|
||||
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
|
||||
//an assembly that is ok.
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var assemblyName in domainAssemblyNames)
|
||||
{
|
||||
try
|
||||
{
|
||||
var foundAssembly = safeDomainAssemblies.FirstOrDefault(a => a.GetAssemblyFile() == assemblyName.GetAssemblyFile());
|
||||
if (foundAssembly != null)
|
||||
{
|
||||
binFolderAssemblies.Add(foundAssembly);
|
||||
}
|
||||
}
|
||||
catch (SecurityException)
|
||||
{
|
||||
//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
|
||||
//an assembly that is ok.
|
||||
}
|
||||
}
|
||||
|
||||
_binFolderAssemblies = new ReadOnlyCollection<Assembly>(binFolderAssemblies);
|
||||
}
|
||||
}
|
||||
return _binFolderAssemblies;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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>
|
||||
/// <param name="excludeFromResults"></param>
|
||||
/// <returns></returns>
|
||||
internal static IEnumerable<Assembly> GetAssembliesWithKnownExclusions(
|
||||
IEnumerable<Assembly> excludeFromResults = null)
|
||||
{
|
||||
if (LocalFilteredAssemblyCache.Any()) return LocalFilteredAssemblyCache;
|
||||
using (new WriteLock(LocalFilteredAssemblyCacheLocker))
|
||||
{
|
||||
var assemblies = GetFilteredAssemblies(excludeFromResults, KnownAssemblyExclusionFilter);
|
||||
foreach (var assembly in assemblies) LocalFilteredAssemblyCache.Add(assembly);
|
||||
}
|
||||
return LocalFilteredAssemblyCache;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a list of found local Assemblies and exluding the ones passed in and excluding the exclusion list filter
|
||||
/// </summary>
|
||||
/// <param name="excludeFromResults"></param>
|
||||
/// <param name="exclusionFilter"></param>
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<Assembly> GetFilteredAssemblies(
|
||||
IEnumerable<Assembly> excludeFromResults = null,
|
||||
string[] exclusionFilter = null)
|
||||
{
|
||||
if (excludeFromResults == null)
|
||||
excludeFromResults = new List<Assembly>();
|
||||
if (exclusionFilter == null)
|
||||
exclusionFilter = new string[] { };
|
||||
|
||||
return GetAllAssemblies()
|
||||
.Where(x => !excludeFromResults.Contains(x)
|
||||
&& !x.GlobalAssemblyCache
|
||||
&& !exclusionFilter.Any(f => x.FullName.StartsWith(f)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// this is our assembly filter to filter out known types that def dont contain types we'd like to find or plugins
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// NOTE the comma vs period... comma delimits the name in an Assembly FullName property so if it ends with comma then its an exact name match
|
||||
/// </remarks>
|
||||
internal static readonly string[] KnownAssemblyExclusionFilter = new[]
|
||||
{
|
||||
"mscorlib,",
|
||||
"System.",
|
||||
"Antlr3.",
|
||||
"Autofac.",
|
||||
"Autofac,",
|
||||
"Castle.",
|
||||
"ClientDependency.",
|
||||
"DataAnnotationsExtensions.",
|
||||
"DataAnnotationsExtensions,",
|
||||
"Dynamic,",
|
||||
"HtmlDiff,",
|
||||
"Iesi.Collections,",
|
||||
"Microsoft.",
|
||||
"Newtonsoft.",
|
||||
"NHibernate.",
|
||||
"NHibernate,",
|
||||
"NuGet.",
|
||||
"RouteDebugger,",
|
||||
"SqlCE4Umbraco,",
|
||||
"umbraco.datalayer,",
|
||||
"umbraco.interfaces,",
|
||||
"umbraco.providers,",
|
||||
"Umbraco.Web.UI,",
|
||||
"Lucene.",
|
||||
"Examine,",
|
||||
"Examine.",
|
||||
"ServiceStack.",
|
||||
"MySql.",
|
||||
"HtmlAgilityPack.",
|
||||
"TidyNet.",
|
||||
"ICSharpCode.",
|
||||
"CookComputing.",
|
||||
/* Mono */
|
||||
"MonoDevelop.NUnit",
|
||||
"Serilog."
|
||||
};
|
||||
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>()
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return FindClassesOfTypeWithAttribute<T, TAttribute>(GetAssembliesWithKnownExclusions(), true);
|
||||
}
|
||||
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(IEnumerable<Assembly> assemblies)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return FindClassesOfTypeWithAttribute<T, TAttribute>(assemblies, true);
|
||||
}
|
||||
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException("assemblies");
|
||||
|
||||
var l = new List<Type>();
|
||||
foreach (var a in assemblies)
|
||||
{
|
||||
var types = from t in GetTypesWithFormattedException(a)
|
||||
where !t.IsInterface
|
||||
&& typeof(T).IsAssignableFrom(t)
|
||||
&& t.GetCustomAttributes<TAttribute>(false).Any()
|
||||
&& (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract))
|
||||
select t;
|
||||
l.AddRange(types);
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches all filtered local assemblies specified for classes of the type passed in.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>()
|
||||
{
|
||||
return FindClassesOfType<T>(GetAssembliesWithKnownExclusions(), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all types found of in the assemblies specified of type T
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException("assemblies");
|
||||
|
||||
return GetAssignablesFromType<T>(assemblies, onlyConcreteClasses);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all types found of in the assemblies specified of type T
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>(IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
return FindClassesOfType<T>(assemblies, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <param name="onlyConcreteClasses">if set to <c>true</c> only concrete classes.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
|
||||
where T : Attribute
|
||||
{
|
||||
return FindClassesWithAttribute(typeof(T), assemblies, onlyConcreteClasses);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute.
|
||||
/// </summary>
|
||||
/// <param name="type">The attribute type </param>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <param name="onlyConcreteClasses">if set to <c>true</c> only concrete classes.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute(Type type, IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException("assemblies");
|
||||
if (!TypeHelper.IsTypeAssignableFrom<Attribute>(type))
|
||||
throw new ArgumentException("The type specified: " + type + " is not an Attribute type");
|
||||
|
||||
var l = new List<Type>();
|
||||
foreach (var a in assemblies)
|
||||
{
|
||||
var types = from t in GetTypesWithFormattedException(a)
|
||||
where !t.IsInterface && t.GetCustomAttributes(type, false).Any() && (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract))
|
||||
select t;
|
||||
l.AddRange(types);
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>(IEnumerable<Assembly> assemblies)
|
||||
where T : Attribute
|
||||
{
|
||||
return FindClassesWithAttribute<T>(assemblies, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute in filtered local assemblies
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>()
|
||||
where T : Attribute
|
||||
{
|
||||
return FindClassesWithAttribute<T>(GetAssembliesWithKnownExclusions());
|
||||
}
|
||||
|
||||
|
||||
#region Private methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of assignables of type T from a collection of assemblies
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<Type> GetAssignablesFromType<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
|
||||
{
|
||||
return GetTypes(typeof(T), assemblies, onlyConcreteClasses);
|
||||
}
|
||||
|
||||
private static IEnumerable<Type> GetTypes(Type assignTypeFrom, IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
|
||||
{
|
||||
var l = new List<Type>();
|
||||
foreach (var a in assemblies)
|
||||
{
|
||||
var types = from t in GetTypesWithFormattedException(a)
|
||||
where !t.IsInterface && assignTypeFrom.IsAssignableFrom(t) && (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract))
|
||||
select t;
|
||||
l.AddRange(types);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
private static IEnumerable<Type> GetTypesWithFormattedException(Assembly a)
|
||||
{
|
||||
//if the assembly is dynamic, do not try to scan it
|
||||
if (a.IsDynamic)
|
||||
return Enumerable.Empty<Type>();
|
||||
|
||||
try
|
||||
{
|
||||
return a.GetExportedTypes();
|
||||
}
|
||||
catch (ReflectionTypeLoadException ex)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("Could not load types from assembly " + a.FullName + ", errors:");
|
||||
foreach (var loaderException in ex.LoaderExceptions.WhereNotNull())
|
||||
{
|
||||
sb.AppendLine("Exception: " + loaderException.ToString());
|
||||
}
|
||||
throw new ReflectionTypeLoadException(ex.Types, ex.LoaderExceptions, sb.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -27,24 +27,30 @@ namespace Umbraco.Tests.Composing
|
||||
public void Initialize()
|
||||
{
|
||||
// this ensures it's reset
|
||||
_typeLoader = new TypeLoader(NoAppCache.Instance, Current.IOHelper.MapPath("~/App_Data/TEMP"), new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>()), false);
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
_typeLoader = new TypeLoader(IOHelper.Default, typeFinder, NoAppCache.Instance,
|
||||
new DirectoryInfo(IOHelper.Default.MapPath("~/App_Data/TEMP")),
|
||||
new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>()), false,
|
||||
|
||||
// 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
|
||||
new[]
|
||||
{
|
||||
this.GetType().Assembly,
|
||||
typeof(System.Guid).Assembly,
|
||||
typeof(NUnit.Framework.Assert).Assembly,
|
||||
typeof(Microsoft.CSharp.CSharpCodeProvider).Assembly,
|
||||
typeof(System.Xml.NameTable).Assembly,
|
||||
typeof(System.Configuration.GenericEnumConverter).Assembly,
|
||||
typeof(System.Web.SiteMap).Assembly,
|
||||
//typeof(TabPage).Assembly,
|
||||
typeof(System.Web.Mvc.ActionResult).Assembly,
|
||||
typeof(TypeFinder).Assembly,
|
||||
typeof(UmbracoContext).Assembly
|
||||
});
|
||||
|
||||
|
||||
|
||||
// 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
|
||||
_typeLoader.AssembliesToScan = new[]
|
||||
{
|
||||
this.GetType().Assembly,
|
||||
typeof(System.Guid).Assembly,
|
||||
typeof(NUnit.Framework.Assert).Assembly,
|
||||
typeof(Microsoft.CSharp.CSharpCodeProvider).Assembly,
|
||||
typeof(System.Xml.NameTable).Assembly,
|
||||
typeof(System.Configuration.GenericEnumConverter).Assembly,
|
||||
typeof(System.Web.SiteMap).Assembly,
|
||||
//typeof(TabPage).Assembly,
|
||||
typeof(System.Web.Mvc.ActionResult).Assembly,
|
||||
typeof(TypeFinder).Assembly,
|
||||
typeof(UmbracoContext).Assembly
|
||||
};
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
@@ -189,15 +195,15 @@ AnotherContentFinder
|
||||
[Test]
|
||||
public void Create_Cached_Plugin_File()
|
||||
{
|
||||
var types = new[] { typeof (TypeLoader), typeof (TypeLoaderTests), typeof (UmbracoContext) };
|
||||
var types = new[] { typeof(TypeLoader), typeof(TypeLoaderTests), typeof(UmbracoContext) };
|
||||
|
||||
var typeList1 = new TypeLoader.TypeList(typeof (object), null);
|
||||
var typeList1 = new TypeLoader.TypeList(typeof(object), null);
|
||||
foreach (var type in types) typeList1.Add(type);
|
||||
_typeLoader.AddTypeList(typeList1);
|
||||
_typeLoader.WriteCache();
|
||||
|
||||
var plugins = _typeLoader.TryGetCached(typeof (object), null);
|
||||
var diffType = _typeLoader.TryGetCached(typeof (object), typeof (ObsoleteAttribute));
|
||||
var plugins = _typeLoader.TryGetCached(typeof(object), null);
|
||||
var diffType = _typeLoader.TryGetCached(typeof(object), typeof(ObsoleteAttribute));
|
||||
|
||||
Assert.IsTrue(plugins.Success);
|
||||
//this will be false since there is no cache of that type resolution kind
|
||||
@@ -268,7 +274,7 @@ AnotherContentFinder
|
||||
public void GetDataEditors()
|
||||
{
|
||||
var types = _typeLoader.GetDataEditors();
|
||||
Assert.AreEqual(38, types.Count());
|
||||
Assert.AreEqual(37, types.Count());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -280,16 +286,16 @@ AnotherContentFinder
|
||||
{
|
||||
var types = new HashSet<TypeLoader.TypeList>();
|
||||
|
||||
var propEditors = new TypeLoader.TypeList(typeof (DataEditor), null);
|
||||
var propEditors = new TypeLoader.TypeList(typeof(DataEditor), null);
|
||||
propEditors.Add(typeof(LabelPropertyEditor));
|
||||
types.Add(propEditors);
|
||||
|
||||
var found = types.SingleOrDefault(x => x.BaseType == typeof (DataEditor) && x.AttributeType == null);
|
||||
var found = types.SingleOrDefault(x => x.BaseType == typeof(DataEditor) && x.AttributeType == null);
|
||||
|
||||
Assert.IsNotNull(found);
|
||||
|
||||
//This should not find a type list of this type
|
||||
var shouldNotFind = types.SingleOrDefault(x => x.BaseType == typeof (IDataEditor) && x.AttributeType == null);
|
||||
var shouldNotFind = types.SingleOrDefault(x => x.BaseType == typeof(IDataEditor) && x.AttributeType == null);
|
||||
|
||||
Assert.IsNull(shouldNotFind);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Moq;
|
||||
@@ -25,9 +26,10 @@ namespace Umbraco.Tests.CoreThings
|
||||
{
|
||||
// FIXME: bad in a unit test - but Udi has a static ctor that wants it?!
|
||||
var container = new Mock<IFactory>();
|
||||
var globalSettings = SettingsForTests.GenerateMockGlobalSettings();
|
||||
var ioHelper = IOHelper.Default;
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
container.Setup(x => x.GetInstance(typeof(TypeLoader))).Returns(
|
||||
new TypeLoader(NoAppCache.Instance, Current.IOHelper.MapPath("~/App_Data/TEMP"), new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>())));
|
||||
new TypeLoader(ioHelper, typeFinder, NoAppCache.Instance, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>())));
|
||||
Current.Factory = container.Object;
|
||||
|
||||
Udi.ResetUdiTypes();
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Umbraco.Tests.IO
|
||||
{
|
||||
_register = RegisterFactory.Create();
|
||||
|
||||
var composition = new Composition(_register, new TypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
var composition = new Composition(_register, TestHelper.GetMockedTypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
|
||||
composition.Register(_ => Mock.Of<ILogger>());
|
||||
composition.Register(_ => Mock.Of<IDataTypeService>());
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using NUnit.Framework;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Web.Macros;
|
||||
@@ -15,11 +17,12 @@ namespace Umbraco.Tests.Macros
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
//we DO want cache enabled for these tests
|
||||
var cacheHelper = new AppCaches(
|
||||
new ObjectCacheAppCache(),
|
||||
new ObjectCacheAppCache(typeFinder),
|
||||
NoAppCache.Instance,
|
||||
new IsolatedCaches(type => new ObjectCacheAppCache()));
|
||||
new IsolatedCaches(type => new ObjectCacheAppCache(typeFinder)));
|
||||
//Current.ApplicationContext = new ApplicationContext(cacheHelper, new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>()));
|
||||
|
||||
Current.Reset();
|
||||
|
||||
@@ -9,6 +9,7 @@ using Newtonsoft.Json;
|
||||
using Umbraco.Core;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Composing.CompositionExtensions;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -269,7 +270,7 @@ namespace Umbraco.Tests.Models
|
||||
content.UpdateDate = DateTime.Now;
|
||||
content.WriterId = 23;
|
||||
|
||||
var runtimeCache = new ObjectCacheAppCache();
|
||||
var runtimeCache = new ObjectCacheAppCache(new TypeFinder(Mock.Of<ILogger>()));
|
||||
runtimeCache.Insert(content.Id.ToString(CultureInfo.InvariantCulture), () => content);
|
||||
|
||||
var proflog = GetTestProfilingLogger();
|
||||
|
||||
@@ -77,9 +77,9 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
public void CacheActiveForIntsAndGuids()
|
||||
{
|
||||
var realCache = new AppCaches(
|
||||
new ObjectCacheAppCache(),
|
||||
new ObjectCacheAppCache(TypeFinder),
|
||||
new DictionaryAppCache(),
|
||||
new IsolatedCaches(t => new ObjectCacheAppCache()));
|
||||
new IsolatedCaches(t => new ObjectCacheAppCache(TypeFinder)));
|
||||
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (var scope = provider.CreateScope())
|
||||
|
||||
@@ -49,9 +49,9 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
MediaTypeRepository mediaTypeRepository;
|
||||
|
||||
var realCache = new AppCaches(
|
||||
new ObjectCacheAppCache(),
|
||||
new ObjectCacheAppCache(TypeFinder),
|
||||
new DictionaryAppCache(),
|
||||
new IsolatedCaches(t => new ObjectCacheAppCache()));
|
||||
new IsolatedCaches(t => new ObjectCacheAppCache(TypeFinder)));
|
||||
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (var scope = provider.CreateScope())
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
try
|
||||
{
|
||||
var container = RegisterFactory.Create();
|
||||
var composition = new Composition(container, new TypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
|
||||
composition.WithCollectionBuilder<PropertyValueConverterCollectionBuilder>();
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
|
||||
|
||||
var register = RegisterFactory.Create();
|
||||
var composition = new Composition(register, new TypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
var composition = new Composition(register, TestHelper.GetMockedTypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
|
||||
register.Register<IShortStringHelper>(_
|
||||
=> new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings())));
|
||||
|
||||
@@ -178,7 +178,7 @@ namespace Umbraco.Tests.Published
|
||||
Current.Reset();
|
||||
var register = RegisterFactory.Create();
|
||||
|
||||
var composition = new Composition(register, new TypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
var composition = new Composition(register, TestHelper.GetMockedTypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
|
||||
composition.WithCollectionBuilder<PropertyValueConverterCollectionBuilder>()
|
||||
.Append<SimpleConverter3A>()
|
||||
|
||||
@@ -4,6 +4,7 @@ using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
@@ -124,8 +125,9 @@ namespace Umbraco.Tests.Published
|
||||
|
||||
var setType1 = publishedContentTypeFactory.CreateContentType(1000, "set1", CreatePropertyTypes);
|
||||
|
||||
var elementsCache = new FastDictionaryAppCache();
|
||||
var snapshotCache = new FastDictionaryAppCache();
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
var elementsCache = new FastDictionaryAppCache(typeFinder);
|
||||
var snapshotCache = new FastDictionaryAppCache(typeFinder);
|
||||
|
||||
var publishedSnapshot = new Mock<IPublishedSnapshot>();
|
||||
publishedSnapshot.Setup(x => x.SnapshotCache).Returns(snapshotCache);
|
||||
@@ -144,39 +146,39 @@ namespace Umbraco.Tests.Published
|
||||
Assert.AreEqual(1, converter.SourceConverts);
|
||||
Assert.AreEqual(1, converter.InterConverts);
|
||||
|
||||
Assert.AreEqual(elementsCount1, elementsCache.Items.Count);
|
||||
Assert.AreEqual(snapshotCount1, snapshotCache.Items.Count);
|
||||
Assert.AreEqual(elementsCount1, elementsCache.Count);
|
||||
Assert.AreEqual(snapshotCount1, snapshotCache.Count);
|
||||
|
||||
Assert.AreEqual(1234, set1.Value("prop1"));
|
||||
Assert.AreEqual(1, converter.SourceConverts);
|
||||
Assert.AreEqual(interConverts, converter.InterConverts);
|
||||
|
||||
Assert.AreEqual(elementsCount2, elementsCache.Items.Count);
|
||||
Assert.AreEqual(snapshotCount2, snapshotCache.Items.Count);
|
||||
Assert.AreEqual(elementsCount2, elementsCache.Count);
|
||||
Assert.AreEqual(snapshotCount2, snapshotCache.Count);
|
||||
|
||||
var oldSnapshotCache = snapshotCache;
|
||||
snapshotCache.Items.Clear();
|
||||
snapshotCache.Clear();
|
||||
|
||||
Assert.AreEqual(1234, set1.Value("prop1"));
|
||||
Assert.AreEqual(1, converter.SourceConverts);
|
||||
|
||||
Assert.AreEqual(elementsCount2, elementsCache.Items.Count);
|
||||
Assert.AreEqual(snapshotCount2, snapshotCache.Items.Count);
|
||||
Assert.AreEqual(snapshotCount2, oldSnapshotCache.Items.Count);
|
||||
Assert.AreEqual(elementsCount2, elementsCache.Count);
|
||||
Assert.AreEqual(snapshotCount2, snapshotCache.Count);
|
||||
Assert.AreEqual(snapshotCount2, oldSnapshotCache.Count);
|
||||
|
||||
Assert.AreEqual((interConverts == 1 ? 1 : 3) + snapshotCache.Items.Count, converter.InterConverts);
|
||||
Assert.AreEqual((interConverts == 1 ? 1 : 3) + snapshotCache.Count, converter.InterConverts);
|
||||
|
||||
var oldElementsCache = elementsCache;
|
||||
elementsCache.Items.Clear();
|
||||
elementsCache.Clear();
|
||||
|
||||
Assert.AreEqual(1234, set1.Value("prop1"));
|
||||
Assert.AreEqual(1, converter.SourceConverts);
|
||||
|
||||
Assert.AreEqual(elementsCount2, elementsCache.Items.Count);
|
||||
Assert.AreEqual(elementsCount2, oldElementsCache.Items.Count);
|
||||
Assert.AreEqual(snapshotCount2, snapshotCache.Items.Count);
|
||||
Assert.AreEqual(elementsCount2, elementsCache.Count);
|
||||
Assert.AreEqual(elementsCount2, oldElementsCache.Count);
|
||||
Assert.AreEqual(snapshotCount2, snapshotCache.Count);
|
||||
|
||||
Assert.AreEqual((interConverts == 1 ? 1 : 4) + snapshotCache.Items.Count + elementsCache.Items.Count, converter.InterConverts);
|
||||
Assert.AreEqual((interConverts == 1 ? 1 : 4) + snapshotCache.Count + elementsCache.Count, converter.InterConverts);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -138,6 +138,8 @@ namespace Umbraco.Tests.PublishedContent
|
||||
// create a data source for NuCache
|
||||
_source = new TestDataSource(kits);
|
||||
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
|
||||
// at last, create the complete NuCache snapshot service!
|
||||
var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true };
|
||||
_snapshotService = new PublishedSnapshotService(options,
|
||||
@@ -158,7 +160,8 @@ namespace Umbraco.Tests.PublishedContent
|
||||
globalSettings,
|
||||
Mock.Of<IEntityXmlSerializer>(),
|
||||
Mock.Of<IPublishedModelFactory>(),
|
||||
new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() }));
|
||||
new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() }),
|
||||
typeFinder);
|
||||
|
||||
// invariant is the current default
|
||||
_variationAccesor.VariationContext = new VariationContext();
|
||||
|
||||
@@ -181,6 +181,8 @@ namespace Umbraco.Tests.PublishedContent
|
||||
// create a variation accessor
|
||||
_variationAccesor = new TestVariationContextAccessor();
|
||||
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
|
||||
// at last, create the complete NuCache snapshot service!
|
||||
var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true };
|
||||
_snapshotService = new PublishedSnapshotService(options,
|
||||
@@ -201,7 +203,8 @@ namespace Umbraco.Tests.PublishedContent
|
||||
globalSettings,
|
||||
Mock.Of<IEntityXmlSerializer>(),
|
||||
Mock.Of<IPublishedModelFactory>(),
|
||||
new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() }));
|
||||
new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() }),
|
||||
typeFinder);
|
||||
|
||||
// invariant is the current default
|
||||
_variationAccesor.VariationContext = new VariationContext();
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Web.Routing;
|
||||
using Moq;
|
||||
using Umbraco.Core;
|
||||
@@ -12,6 +14,7 @@ using Umbraco.Core.Composing;
|
||||
using Current = Umbraco.Core.Composing.Current;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
@@ -41,16 +44,15 @@ namespace Umbraco.Tests.PublishedContent
|
||||
Composition.RegisterUnique<IPublishedModelFactory>(f => new PublishedModelFactory(f.GetInstance<TypeLoader>().GetTypes<PublishedContentModel>()));
|
||||
}
|
||||
|
||||
protected override TypeLoader CreateTypeLoader(IAppPolicyCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger)
|
||||
protected override TypeLoader CreateTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger)
|
||||
{
|
||||
var pluginManager = base.CreateTypeLoader(runtimeCache, globalSettings, logger);
|
||||
var baseLoader = base.CreateTypeLoader(ioHelper, typeFinder, runtimeCache, globalSettings, logger);
|
||||
|
||||
// this is so the model factory looks into the test assembly
|
||||
pluginManager.AssembliesToScan = pluginManager.AssembliesToScan
|
||||
.Union(new[] { typeof (PublishedContentMoreTests).Assembly })
|
||||
.ToList();
|
||||
|
||||
return pluginManager;
|
||||
return new TypeLoader(ioHelper, typeFinder, runtimeCache, new DirectoryInfo(globalSettings.LocalTempPath), logger, false,
|
||||
// this is so the model factory looks into the test assembly
|
||||
baseLoader.AssembliesToScan
|
||||
.Union(new[] {typeof(PublishedContentMoreTests).Assembly})
|
||||
.ToList());
|
||||
}
|
||||
|
||||
private UmbracoContext GetUmbracoContext()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using NUnit.Framework;
|
||||
@@ -14,6 +15,7 @@ using Moq;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
@@ -83,16 +85,16 @@ namespace Umbraco.Tests.PublishedContent
|
||||
ContentTypesCache.GetPublishedContentTypeByAlias = alias => alias.InvariantEquals("home") ? homeType : anythingType;
|
||||
}
|
||||
|
||||
protected override TypeLoader CreateTypeLoader(IAppPolicyCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger)
|
||||
|
||||
protected override TypeLoader CreateTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger)
|
||||
{
|
||||
var pluginManager = base.CreateTypeLoader(runtimeCache, globalSettings, logger);
|
||||
var baseLoader = base.CreateTypeLoader(ioHelper, typeFinder, runtimeCache, globalSettings, logger);
|
||||
|
||||
// this is so the model factory looks into the test assembly
|
||||
pluginManager.AssembliesToScan = pluginManager.AssembliesToScan
|
||||
.Union(new[] { typeof(PublishedContentTests).Assembly })
|
||||
.ToList();
|
||||
|
||||
return pluginManager;
|
||||
return new TypeLoader(ioHelper, typeFinder, runtimeCache, new DirectoryInfo(globalSettings.LocalTempPath), logger, false,
|
||||
// this is so the model factory looks into the test assembly
|
||||
baseLoader.AssembliesToScan
|
||||
.Union(new[] { typeof(PublishedContentTests).Assembly })
|
||||
.ToList());
|
||||
}
|
||||
|
||||
private readonly Guid _node1173Guid = Guid.NewGuid();
|
||||
|
||||
@@ -61,14 +61,16 @@ namespace Umbraco.Tests.Runtimes
|
||||
var profilingLogger = new ProfilingLogger(logger, profiler);
|
||||
var appCaches = AppCaches.Disabled;
|
||||
var databaseFactory = new UmbracoDatabaseFactory(logger, new Lazy<IMapperCollection>(() => factory.GetInstance<IMapperCollection>()));
|
||||
var typeLoader = new TypeLoader(appCaches.RuntimeCache, Current.IOHelper.MapPath("~/App_Data/TEMP"), profilingLogger);
|
||||
var typeFinder = new TypeFinder(logger);
|
||||
var ioHelper = IOHelper.Default;
|
||||
var typeLoader = new TypeLoader(ioHelper, typeFinder, appCaches.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), profilingLogger);
|
||||
var mainDom = new SimpleMainDom();
|
||||
var runtimeState = new RuntimeState(logger, null, null, new Lazy<IMainDom>(() => mainDom), new Lazy<IServerRegistrar>(() => factory.GetInstance<IServerRegistrar>()));
|
||||
|
||||
// create the register and the composition
|
||||
var register = RegisterFactory.Create();
|
||||
var composition = new Composition(register, typeLoader, profilingLogger, runtimeState);
|
||||
composition.RegisterEssentials(logger, profiler, profilingLogger, mainDom, appCaches, databaseFactory, typeLoader, runtimeState, new IOHelper());
|
||||
composition.RegisterEssentials(logger, profiler, profilingLogger, mainDom, appCaches, databaseFactory, typeLoader, runtimeState, typeFinder, ioHelper);
|
||||
|
||||
// create the core runtime and have it compose itself
|
||||
var coreRuntime = new CoreRuntime();
|
||||
@@ -249,7 +251,9 @@ namespace Umbraco.Tests.Runtimes
|
||||
var profilingLogger = new ProfilingLogger(logger, profiler);
|
||||
var appCaches = AppCaches.Disabled;
|
||||
var databaseFactory = Mock.Of<IUmbracoDatabaseFactory>();
|
||||
var typeLoader = new TypeLoader(appCaches.RuntimeCache, Current.IOHelper.MapPath("~/App_Data/TEMP"), profilingLogger);
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
var ioHelper = IOHelper.Default;
|
||||
var typeLoader = new TypeLoader(ioHelper, typeFinder, appCaches.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), profilingLogger);
|
||||
var runtimeState = Mock.Of<IRuntimeState>();
|
||||
Mock.Get(runtimeState).Setup(x => x.Level).Returns(RuntimeLevel.Run);
|
||||
var mainDom = Mock.Of<IMainDom>();
|
||||
@@ -258,7 +262,7 @@ namespace Umbraco.Tests.Runtimes
|
||||
// create the register and the composition
|
||||
var register = RegisterFactory.Create();
|
||||
var composition = new Composition(register, typeLoader, profilingLogger, runtimeState);
|
||||
composition.RegisterEssentials(logger, profiler, profilingLogger, mainDom, appCaches, databaseFactory, typeLoader, runtimeState, new IOHelper());
|
||||
composition.RegisterEssentials(logger, profiler, profilingLogger, mainDom, appCaches, databaseFactory, typeLoader, runtimeState, typeFinder, ioHelper);
|
||||
|
||||
// create the core runtime and have it compose itself
|
||||
var coreRuntime = new CoreRuntime();
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Umbraco.Tests.Scoping
|
||||
|
||||
var register = RegisterFactory.Create();
|
||||
|
||||
var composition = new Composition(register, new TypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
var composition = new Composition(register, TestHelper.GetMockedTypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
|
||||
_testObjects = new TestObjects(register);
|
||||
|
||||
|
||||
@@ -82,6 +82,8 @@ namespace Umbraco.Tests.Scoping
|
||||
var mediaRepository = Mock.Of<IMediaRepository>();
|
||||
var memberRepository = Mock.Of<IMemberRepository>();
|
||||
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
|
||||
return new PublishedSnapshotService(
|
||||
options,
|
||||
null,
|
||||
@@ -99,7 +101,8 @@ namespace Umbraco.Tests.Scoping
|
||||
Factory.GetInstance<IGlobalSettings>(),
|
||||
Factory.GetInstance<IEntityXmlSerializer>(),
|
||||
Mock.Of<IPublishedModelFactory>(),
|
||||
new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() }));
|
||||
new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() }),
|
||||
typeFinder);
|
||||
}
|
||||
|
||||
protected UmbracoContext GetUmbracoContextNu(string url, int templateId = 1234, RouteData routeData = null, bool setSingleton = false, IUmbracoSettingsSection umbracoSettings = null, IEnumerable<IUrlProvider> urlProviders = null)
|
||||
|
||||
@@ -43,9 +43,9 @@ namespace Umbraco.Tests.Scoping
|
||||
{
|
||||
// this is what's created core web runtime
|
||||
return new AppCaches(
|
||||
new DeepCloneAppCache(new ObjectCacheAppCache()),
|
||||
new DeepCloneAppCache(new ObjectCacheAppCache(TypeFinder)),
|
||||
NoAppCache.Instance,
|
||||
new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache())));
|
||||
new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache(TypeFinder))));
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
|
||||
@@ -8,6 +8,7 @@ using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.Persistence;
|
||||
@@ -53,6 +54,8 @@ namespace Umbraco.Tests.Services
|
||||
var mediaRepository = Mock.Of<IMediaRepository>();
|
||||
var memberRepository = Mock.Of<IMemberRepository>();
|
||||
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
|
||||
return new PublishedSnapshotService(
|
||||
options,
|
||||
null,
|
||||
@@ -70,7 +73,8 @@ namespace Umbraco.Tests.Services
|
||||
Factory.GetInstance<IGlobalSettings>(),
|
||||
Factory.GetInstance<IEntityXmlSerializer>(),
|
||||
Mock.Of<IPublishedModelFactory>(),
|
||||
new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() }));
|
||||
new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() }),
|
||||
typeFinder);
|
||||
}
|
||||
|
||||
public class LocalServerMessenger : ServerMessengerBase
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Moq;
|
||||
using NPoco;
|
||||
using NUnit.Framework;
|
||||
@@ -36,9 +37,11 @@ namespace Umbraco.Tests.TestHelpers
|
||||
|
||||
var container = RegisterFactory.Create();
|
||||
|
||||
var ioHelper = IOHelper.Default;
|
||||
var logger = new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>());
|
||||
var typeLoader = new TypeLoader(NoAppCache.Instance,
|
||||
Current.IOHelper.MapPath("~/App_Data/TEMP"),
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
var typeLoader = new TypeLoader(ioHelper, typeFinder, NoAppCache.Instance,
|
||||
new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")),
|
||||
logger,
|
||||
false);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Reflection;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using System.Web.SessionState;
|
||||
using Moq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Composing;
|
||||
@@ -38,7 +39,8 @@ namespace Umbraco.Tests.TestHelpers.Stubs
|
||||
{
|
||||
if (_factory != null) return _factory(requestContext);
|
||||
|
||||
var types = TypeFinder.FindClassesOfType<ControllerBase>(new[] { Assembly.GetExecutingAssembly() });
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
var types = typeFinder.FindClassesOfType<ControllerBase>(new[] { Assembly.GetExecutingAssembly() });
|
||||
|
||||
var controllerTypes = types.Where(x => x.Name.Equals(controllerName + "Controller", StringComparison.InvariantCultureIgnoreCase));
|
||||
var t = controllerTypes.SingleOrDefault();
|
||||
|
||||
@@ -7,10 +7,13 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
@@ -24,13 +27,16 @@ namespace Umbraco.Tests.TestHelpers
|
||||
public static class TestHelper
|
||||
{
|
||||
|
||||
|
||||
public static TypeLoader GetMockedTypeLoader()
|
||||
{
|
||||
return new TypeLoader(IOHelper.Default, Mock.Of<ITypeFinder>(), Mock.Of<IAppPolicyCache>(), new DirectoryInfo(IOHelper.Default.MapPath("~/App_Data/TEMP")), Mock.Of<IProfilingLogger>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current assembly directory.
|
||||
/// </summary>
|
||||
/// <value>The assembly directory.</value>
|
||||
static public string CurrentAssemblyDirectory
|
||||
public static string CurrentAssemblyDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
@@ -230,7 +230,7 @@ namespace Umbraco.Tests.TestHelpers
|
||||
return container?.TryGetInstance<T>() ?? Mock.Of<T>();
|
||||
}
|
||||
|
||||
public IScopeProvider GetScopeProvider(ILogger logger, FileSystems fileSystems = null, IUmbracoDatabaseFactory databaseFactory = null)
|
||||
public IScopeProvider GetScopeProvider(ILogger logger, ITypeFinder typeFinder = null, FileSystems fileSystems = null, IUmbracoDatabaseFactory databaseFactory = null)
|
||||
{
|
||||
if (databaseFactory == null)
|
||||
{
|
||||
@@ -241,8 +241,9 @@ namespace Umbraco.Tests.TestHelpers
|
||||
databaseFactory = new UmbracoDatabaseFactory(Constants.System.UmbracoConnectionName, logger, new Lazy<IMapperCollection>(() => mappers));
|
||||
}
|
||||
|
||||
typeFinder = typeFinder ?? new TypeFinder(logger);
|
||||
fileSystems = fileSystems ?? new FileSystems(Current.Factory, logger);
|
||||
var scopeProvider = new ScopeProvider(databaseFactory, fileSystems, logger);
|
||||
var scopeProvider = new ScopeProvider(databaseFactory, fileSystems, logger, typeFinder);
|
||||
return scopeProvider;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,6 +101,8 @@ namespace Umbraco.Tests.Testing
|
||||
|
||||
protected IIOHelper IOHelper { get; private set; }
|
||||
|
||||
protected ITypeFinder TypeFinder { get; private set; }
|
||||
|
||||
protected IProfiler Profiler => Factory.GetInstance<IProfiler>();
|
||||
|
||||
protected virtual IProfilingLogger ProfilingLogger => Factory.GetInstance<IProfilingLogger>();
|
||||
@@ -131,16 +133,19 @@ namespace Umbraco.Tests.Testing
|
||||
|
||||
var (logger, profiler) = GetLoggers(Options.Logger);
|
||||
var proflogger = new ProfilingLogger(logger, profiler);
|
||||
IOHelper = new IOHelper();
|
||||
IOHelper = Umbraco.Core.IO.IOHelper.Default;
|
||||
TypeFinder = new TypeFinder(logger);
|
||||
var appCaches = GetAppCaches();
|
||||
var globalSettings = SettingsForTests.GetDefaultGlobalSettings();
|
||||
var typeLoader = GetTypeLoader(appCaches.RuntimeCache, globalSettings, proflogger, Options.TypeLoader);
|
||||
var typeLoader = GetTypeLoader(IOHelper, TypeFinder, appCaches.RuntimeCache, globalSettings, proflogger, Options.TypeLoader);
|
||||
|
||||
var register = RegisterFactory.Create();
|
||||
|
||||
Composition = new Composition(register, typeLoader, proflogger, ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
|
||||
|
||||
Composition.RegisterUnique(IOHelper);
|
||||
Composition.RegisterUnique(TypeFinder);
|
||||
Composition.RegisterUnique(typeLoader);
|
||||
Composition.RegisterUnique(logger);
|
||||
Composition.RegisterUnique(profiler);
|
||||
@@ -270,38 +275,35 @@ namespace Umbraco.Tests.Testing
|
||||
.ComposeWebMappingProfiles();
|
||||
}
|
||||
|
||||
protected virtual TypeLoader GetTypeLoader(IAppPolicyCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger, UmbracoTestOptions.TypeLoader option)
|
||||
protected virtual TypeLoader GetTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger, UmbracoTestOptions.TypeLoader option)
|
||||
{
|
||||
switch (option)
|
||||
{
|
||||
case UmbracoTestOptions.TypeLoader.Default:
|
||||
return _commonTypeLoader ?? (_commonTypeLoader = CreateCommonTypeLoader(runtimeCache, globalSettings, logger));
|
||||
return _commonTypeLoader ?? (_commonTypeLoader = CreateCommonTypeLoader(ioHelper, typeFinder, runtimeCache, globalSettings, logger));
|
||||
case UmbracoTestOptions.TypeLoader.PerFixture:
|
||||
return _featureTypeLoader ?? (_featureTypeLoader = CreateTypeLoader(runtimeCache, globalSettings, logger));
|
||||
return _featureTypeLoader ?? (_featureTypeLoader = CreateTypeLoader(ioHelper, typeFinder, runtimeCache, globalSettings, logger));
|
||||
case UmbracoTestOptions.TypeLoader.PerTest:
|
||||
return CreateTypeLoader(runtimeCache, globalSettings, logger);
|
||||
return CreateTypeLoader(ioHelper, typeFinder, runtimeCache, globalSettings, logger);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(option));
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual TypeLoader CreateTypeLoader(IAppPolicyCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger)
|
||||
protected virtual TypeLoader CreateTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger)
|
||||
{
|
||||
return CreateCommonTypeLoader(runtimeCache, globalSettings, logger);
|
||||
return CreateCommonTypeLoader(ioHelper, typeFinder, runtimeCache, globalSettings, logger);
|
||||
}
|
||||
|
||||
// common to all tests = cannot be overriden
|
||||
private static TypeLoader CreateCommonTypeLoader(IAppPolicyCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger)
|
||||
private static TypeLoader CreateCommonTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger)
|
||||
{
|
||||
return new TypeLoader(runtimeCache, globalSettings.LocalTempPath, logger, false)
|
||||
return new TypeLoader(ioHelper, typeFinder, runtimeCache, new DirectoryInfo(globalSettings.LocalTempPath), logger, false, new[]
|
||||
{
|
||||
AssembliesToScan = new[]
|
||||
{
|
||||
Assembly.Load("Umbraco.Core"),
|
||||
Assembly.Load("Umbraco.Web"),
|
||||
Assembly.Load("Umbraco.Tests")
|
||||
}
|
||||
};
|
||||
Assembly.Load("Umbraco.Core"),
|
||||
Assembly.Load("Umbraco.Web"),
|
||||
Assembly.Load("Umbraco.Tests")
|
||||
});
|
||||
}
|
||||
|
||||
protected virtual void ComposeDatabase(UmbracoTestOptions.Database option)
|
||||
@@ -362,7 +364,7 @@ namespace Umbraco.Tests.Testing
|
||||
Composition.WithCollectionBuilder<UrlSegmentProviderCollectionBuilder>(); // empty
|
||||
|
||||
Composition.RegisterUnique(factory
|
||||
=> TestObjects.GetScopeProvider(factory.TryGetInstance<ILogger>(), factory.TryGetInstance<FileSystems>(), factory.TryGetInstance<IUmbracoDatabaseFactory>()));
|
||||
=> TestObjects.GetScopeProvider(factory.TryGetInstance<ILogger>(), factory.TryGetInstance<ITypeFinder>(), factory.TryGetInstance<FileSystems>(), factory.TryGetInstance<IUmbracoDatabaseFactory>()));
|
||||
Composition.RegisterUnique(factory => (IScopeAccessor) factory.GetInstance<IScopeProvider>());
|
||||
|
||||
Composition.ComposeServices();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using Moq;
|
||||
@@ -39,8 +40,10 @@ namespace Umbraco.Tests.Web
|
||||
|
||||
// FIXME: bad in a unit test - but Udi has a static ctor that wants it?!
|
||||
var factory = new Mock<IFactory>();
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
var ioHelper = IOHelper.Default;
|
||||
factory.Setup(x => x.GetInstance(typeof(TypeLoader))).Returns(
|
||||
new TypeLoader(NoAppCache.Instance, Current.IOHelper.MapPath("~/App_Data/TEMP"), new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>())));
|
||||
new TypeLoader(ioHelper, typeFinder, NoAppCache.Instance, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>())));
|
||||
factory.Setup(x => x.GetInstance(typeof (ServiceContext))).Returns(serviceContext);
|
||||
|
||||
var settings = SettingsForTests.GetDefaultUmbracoSettings();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Examine.LuceneEngine;
|
||||
using Lucene.Net.Analysis;
|
||||
@@ -259,13 +260,15 @@ namespace Umbraco.Tests.Web
|
||||
{
|
||||
// FIXME: bad in a unit test - but Udi has a static ctor that wants it?!
|
||||
var container = new Mock<IFactory>();
|
||||
var globalSettings = SettingsForTests.GenerateMockGlobalSettings();
|
||||
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
var ioHelper = IOHelper.Default;
|
||||
container
|
||||
.Setup(x => x.GetInstance(typeof(TypeLoader)))
|
||||
.Returns(new TypeLoader(
|
||||
ioHelper,
|
||||
typeFinder,
|
||||
NoAppCache.Instance,
|
||||
Current.IOHelper.MapPath("~/App_Data/TEMP"),
|
||||
new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")),
|
||||
new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>())
|
||||
)
|
||||
);
|
||||
|
||||
+5
-2
@@ -4,8 +4,11 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Web.Caching;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
namespace Umbraco.Web.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements <see cref="IAppPolicyCache"/> on top of a <see cref="System.Web.Caching.Cache"/>.
|
||||
@@ -23,7 +26,7 @@ namespace Umbraco.Core.Cache
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WebCachingAppCache"/> class.
|
||||
/// </summary>
|
||||
public WebCachingAppCache(System.Web.Caching.Cache cache)
|
||||
public WebCachingAppCache(System.Web.Caching.Cache cache, ITypeFinder typeFinder) : base(typeFinder)
|
||||
{
|
||||
_cache = cache;
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Compilation;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Web.Composing
|
||||
{
|
||||
/// <summary>
|
||||
/// An implementation of TypeFinder that uses the BuildManager to resolve references for aspnet framework hosted websites
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This finder will also try to resolve dynamic assemblies created from App_Code
|
||||
/// </remarks>
|
||||
internal class BuildManagerTypeFinder : TypeFinder, ITypeFinder
|
||||
{
|
||||
|
||||
public BuildManagerTypeFinder(IIOHelper ioHelper, ILogger logger, ITypeFinderConfig typeFinderConfig = null) : base(logger, typeFinderConfig)
|
||||
{
|
||||
if (ioHelper == null) throw new ArgumentNullException(nameof(ioHelper));
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
_allAssemblies = new Lazy<HashSet<Assembly>>(() =>
|
||||
{
|
||||
var isHosted = ioHelper.IsHosted;
|
||||
try
|
||||
{
|
||||
if (isHosted)
|
||||
{
|
||||
var assemblies = new HashSet<Assembly>(BuildManager.GetReferencedAssemblies().Cast<Assembly>());
|
||||
|
||||
//here we are trying to get the App_Code assembly
|
||||
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()))
|
||||
{
|
||||
try
|
||||
{
|
||||
var appCodeAssembly = Assembly.Load("App_Code");
|
||||
if (assemblies.Contains(appCodeAssembly) == false) // BuildManager will find App_Code already
|
||||
assemblies.Add(appCodeAssembly);
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
{
|
||||
//this will occur if it cannot load the assembly
|
||||
logger.Error(typeof(TypeFinder), ex, "Could not load assembly App_Code");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
if (e.InnerException is SecurityException == false)
|
||||
throw;
|
||||
}
|
||||
|
||||
// Not hosted, just use the default implementation
|
||||
return new HashSet<Assembly>(base.AssembliesToScan);
|
||||
});
|
||||
}
|
||||
|
||||
private readonly Lazy<HashSet<Assembly>> _allAssemblies;
|
||||
|
||||
/// <summary>
|
||||
/// Explicitly implement and return result from BuildManager
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
Type ITypeFinder.GetTypeByName (string name) => BuildManager.GetType(name, false);
|
||||
|
||||
/// <summary>
|
||||
/// Explicitly implement and return result from BuildManager
|
||||
/// </summary>
|
||||
IEnumerable<Assembly> ITypeFinder.AssembliesToScan => _allAssemblies.Value;
|
||||
|
||||
/// <summary>
|
||||
/// TypeFinder config via appSettings
|
||||
/// </summary>
|
||||
internal class TypeFinderConfig : ITypeFinderConfig
|
||||
{
|
||||
private IEnumerable<string> _assembliesAcceptingLoadExceptions;
|
||||
public IEnumerable<string> AssembliesAcceptingLoadExceptions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_assembliesAcceptingLoadExceptions != null)
|
||||
return _assembliesAcceptingLoadExceptions;
|
||||
|
||||
var s = ConfigurationManager.AppSettings[Constants.AppSettings.AssembliesAcceptingLoadExceptions];
|
||||
return _assembliesAcceptingLoadExceptions = string.IsNullOrWhiteSpace(s)
|
||||
? Array.Empty<string>()
|
||||
: s.Split(',').Select(x => x.Trim()).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -486,6 +486,7 @@ namespace Umbraco.Web.Editors
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <param name="dataTypeKey"></param>
|
||||
/// <returns></returns>
|
||||
public PagedResult<EntityBasic> GetPagedChildren(
|
||||
string id,
|
||||
|
||||
@@ -8,6 +8,7 @@ using CSharpTest.Net.Collections;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
@@ -46,6 +47,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
private readonly IPublishedModelFactory _publishedModelFactory;
|
||||
private readonly IDefaultCultureAccessor _defaultCultureAccessor;
|
||||
private readonly UrlSegmentProviderCollection _urlSegmentProviders;
|
||||
private readonly ITypeFinder _typeFinder;
|
||||
|
||||
// volatile because we read it with no lock
|
||||
private volatile bool _isReady;
|
||||
@@ -77,7 +79,8 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
IDataSource dataSource, IGlobalSettings globalSettings,
|
||||
IEntityXmlSerializer entitySerializer,
|
||||
IPublishedModelFactory publishedModelFactory,
|
||||
UrlSegmentProviderCollection urlSegmentProviders)
|
||||
UrlSegmentProviderCollection urlSegmentProviders,
|
||||
ITypeFinder typeFinder)
|
||||
: base(publishedSnapshotAccessor, variationContextAccessor)
|
||||
{
|
||||
//if (Interlocked.Increment(ref _singletonCheck) > 1)
|
||||
@@ -94,6 +97,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
_defaultCultureAccessor = defaultCultureAccessor;
|
||||
_globalSettings = globalSettings;
|
||||
_urlSegmentProviders = urlSegmentProviders;
|
||||
_typeFinder = typeFinder;
|
||||
|
||||
// we need an Xml serializer here so that the member cache can support XPath,
|
||||
// for members this is done by navigating the serialized-to-xml member
|
||||
@@ -1162,7 +1166,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
_contentGen = contentSnap.Gen;
|
||||
_mediaGen = mediaSnap.Gen;
|
||||
_domainGen = domainSnap.Gen;
|
||||
elementsCache = _elementsCache = new FastDictionaryAppCache();
|
||||
elementsCache = _elementsCache = new FastDictionaryAppCache(_typeFinder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Runtime;
|
||||
using Umbraco.Web.Cache;
|
||||
using Umbraco.Web.Composing;
|
||||
using Umbraco.Web.Logging;
|
||||
|
||||
namespace Umbraco.Web.Runtime
|
||||
@@ -16,6 +18,7 @@ namespace Umbraco.Web.Runtime
|
||||
{
|
||||
private readonly UmbracoApplicationBase _umbracoApplication;
|
||||
private IProfiler _webProfiler;
|
||||
private BuildManagerTypeFinder _typeFinder;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WebRuntime"/> class.
|
||||
@@ -56,18 +59,20 @@ namespace Umbraco.Web.Runtime
|
||||
|
||||
#region Getters
|
||||
|
||||
protected override ITypeFinder GetTypeFinder() => _typeFinder ?? (_typeFinder = new BuildManagerTypeFinder(IOHelper, Logger, new BuildManagerTypeFinder.TypeFinderConfig()));
|
||||
|
||||
protected override IProfiler GetProfiler() => _webProfiler;
|
||||
|
||||
protected override AppCaches GetAppCaches() => new AppCaches(
|
||||
// we need to have the dep clone runtime cache provider to ensure
|
||||
// all entities are cached properly (cloned in and cloned out)
|
||||
new DeepCloneAppCache(new WebCachingAppCache(HttpRuntime.Cache)),
|
||||
new DeepCloneAppCache(new WebCachingAppCache(HttpRuntime.Cache, TypeFinder)),
|
||||
// we need request based cache when running in web-based context
|
||||
new HttpRequestAppCache(),
|
||||
new HttpRequestAppCache(() => HttpContext.Current?.Items, TypeFinder),
|
||||
new IsolatedCaches(type =>
|
||||
// we need to have the dep clone runtime cache provider to ensure
|
||||
// all entities are cached properly (cloned in and cloned out)
|
||||
new DeepCloneAppCache(new ObjectCacheAppCache())));
|
||||
new DeepCloneAppCache(new ObjectCacheAppCache(TypeFinder))));
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using Lucene.Net.Analysis.Standard;
|
||||
using Examine.LuceneEngine;
|
||||
using Examine;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Web.Search
|
||||
{
|
||||
@@ -17,10 +18,12 @@ namespace Umbraco.Web.Search
|
||||
{
|
||||
// TODO: we should inject the different IValueSetValidator so devs can just register them instead of overriding this class?
|
||||
|
||||
public UmbracoIndexesCreator(IProfilingLogger profilingLogger,
|
||||
public UmbracoIndexesCreator(
|
||||
ITypeFinder typeFinder,
|
||||
IProfilingLogger profilingLogger,
|
||||
ILocalizationService languageService,
|
||||
IPublicAccessService publicAccessService,
|
||||
IMemberService memberService, IUmbracoIndexConfig umbracoIndexConfig)
|
||||
IMemberService memberService, IUmbracoIndexConfig umbracoIndexConfig) : base(typeFinder)
|
||||
{
|
||||
ProfilingLogger = profilingLogger ?? throw new System.ArgumentNullException(nameof(profilingLogger));
|
||||
LanguageService = languageService ?? throw new System.ArgumentNullException(nameof(languageService));
|
||||
|
||||
@@ -130,9 +130,11 @@
|
||||
<Compile Include="Cache\IDistributedCacheBinder.cs" />
|
||||
<Compile Include="Cache\UserGroupCacheRefresher.cs" />
|
||||
<Compile Include="Cache\UserGroupPermissionsCacheRefresher.cs" />
|
||||
<Compile Include="Cache\WebCachingAppCache.cs" />
|
||||
<Compile Include="Compose\BackOfficeUserAuditEventsComposer.cs" />
|
||||
<Compile Include="Compose\NotificationsComposer.cs" />
|
||||
<Compile Include="Compose\PublicAccessComposer.cs" />
|
||||
<Compile Include="Composing\BuildManagerTypeFinder.cs" />
|
||||
<Compile Include="Composing\CompositionExtensions\Installer.cs" />
|
||||
<Compile Include="Composing\LightInject\LightInjectContainer.cs" />
|
||||
<Compile Include="Compose\BackOfficeUserAuditEventsComponent.cs" />
|
||||
|
||||
Reference in New Issue
Block a user