diff --git a/src/Umbraco.Core/ApplicationEventHandler.cs b/src/Umbraco.Core/ApplicationEventHandler.cs
index 8d97baac95..a725a08a8e 100644
--- a/src/Umbraco.Core/ApplicationEventHandler.cs
+++ b/src/Umbraco.Core/ApplicationEventHandler.cs
@@ -74,7 +74,7 @@ namespace Umbraco.Core
///
private bool ShouldExecute(ApplicationContext applicationContext)
{
- if (applicationContext.IsConfigured && applicationContext.DatabaseContext.IsDatabaseConfigured)
+ if (applicationContext.IsConfigured && applicationContext.DatabaseContext.CanConnect)
{
return true;
}
@@ -84,7 +84,7 @@ namespace Umbraco.Core
return true;
}
- if (!applicationContext.DatabaseContext.IsDatabaseConfigured && ExecuteWhenDatabaseNotConfigured)
+ if (!applicationContext.DatabaseContext.CanConnect && ExecuteWhenDatabaseNotConfigured)
{
return true;
}
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IScheduledTasksSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IScheduledTasksSection.cs
index 9d01549a5c..8b25e11e91 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/IScheduledTasksSection.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/IScheduledTasksSection.cs
@@ -5,5 +5,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
public interface IScheduledTasksSection : IUmbracoConfigurationSection
{
IEnumerable Tasks { get; }
+
+ string BaseUrl { get; }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ScheduledTasksElement.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ScheduledTasksElement.cs
index 3571e2d7ed..0598aeec9e 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/ScheduledTasksElement.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/ScheduledTasksElement.cs
@@ -16,5 +16,11 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
{
get { return Tasks; }
}
+
+ [ConfigurationProperty("baseUrl", IsRequired = false, DefaultValue = null)]
+ public string BaseUrl
+ {
+ get { return (string)base["baseUrl"]; }
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/DatabaseContext.cs b/src/Umbraco.Core/DatabaseContext.cs
index 105d006656..fad96b849d 100644
--- a/src/Umbraco.Core/DatabaseContext.cs
+++ b/src/Umbraco.Core/DatabaseContext.cs
@@ -26,6 +26,9 @@ namespace Umbraco.Core
{
private readonly IDatabaseFactory _factory;
private bool _configured;
+ private bool _canConnect;
+ private volatile bool _connectCheck = false;
+ private readonly object _locker = new object();
private string _connectionString;
private string _providerName;
private DatabaseSchemaResult _result;
@@ -56,6 +59,32 @@ namespace Umbraco.Core
get { return _configured; }
}
+ ///
+ /// Determines if the db can be connected to
+ ///
+ public bool CanConnect
+ {
+ get
+ {
+ if (IsDatabaseConfigured == false) return false;
+
+ //double check lock so that it is only checked once and is fast
+ if (_connectCheck == false)
+ {
+ lock (_locker)
+ {
+ if (_canConnect == false)
+ {
+ _canConnect = DbConnectionExtensions.IsConnectionAvailable(ConnectionString, DatabaseProvider);
+ _connectCheck = true;
+ }
+ }
+ }
+
+ return _canConnect;
+ }
+ }
+
///
/// Gets the configured umbraco db connection string.
///
diff --git a/src/Umbraco.Core/Persistence/DbConnectionExtensions.cs b/src/Umbraco.Core/Persistence/DbConnectionExtensions.cs
index f7bd9e31c1..c4ca875eb2 100644
--- a/src/Umbraco.Core/Persistence/DbConnectionExtensions.cs
+++ b/src/Umbraco.Core/Persistence/DbConnectionExtensions.cs
@@ -75,7 +75,7 @@ namespace Umbraco.Core.Persistence
connection.Open();
connection.Close();
}
- catch (SqlException)
+ catch (DbException)
{
return false;
}
diff --git a/src/Umbraco.Core/Services/ApplicationTreeService.cs b/src/Umbraco.Core/Services/ApplicationTreeService.cs
index dbf5c9b85a..5278990d6a 100644
--- a/src/Umbraco.Core/Services/ApplicationTreeService.cs
+++ b/src/Umbraco.Core/Services/ApplicationTreeService.cs
@@ -8,6 +8,7 @@ using Umbraco.Core.Events;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
+using Umbraco.Core.Cache;
using File = System.IO.File;
namespace Umbraco.Core.Services
@@ -15,15 +16,18 @@ namespace Umbraco.Core.Services
internal class ApplicationTreeService : IApplicationTreeService
{
private readonly CacheHelper _cache;
+ private IEnumerable _allAvailableTrees;
+ private volatile bool _isInitialized = false;
+ internal const string TreeConfigFileName = "trees.config";
+ private static string _treeConfig;
+ private static readonly object Locker = new object();
public ApplicationTreeService(CacheHelper cache)
{
_cache = cache;
}
- internal const string TreeConfigFileName = "trees.config";
- private static string _treeConfig;
- private static readonly object Locker = new object();
+
///
/// gets/sets the trees.config file path
@@ -45,74 +49,101 @@ namespace Umbraco.Core.Services
}
///
- /// The cache storage for all application trees
+ /// The main entry point to get application trees
///
+ ///
+ /// This lazily on first access will scan for plugin trees and ensure the trees.config is up-to-date with the plugins. If plugins
+ /// haven't changed on disk then the file will not be saved. The trees are all then loaded from this config file into cache and returned.
+ ///
private List GetAppTrees()
{
- return _cache.GetCacheItem(
+ return _cache.RuntimeCache.GetCacheItem>(
CacheKeys.ApplicationTreeCacheKey,
() =>
+ {
+ var list = ReadFromXmlAndSort();
+
+ //On first access we need to do some initialization
+ if (_isInitialized == false)
{
- var list = new List();
-
- LoadXml(doc =>
+ lock (Locker)
+ {
+ if (_isInitialized == false)
{
- foreach (var addElement in doc.Root.Elements("add").OrderBy(x =>
- {
- var sortOrderAttr = x.Attribute("sortOrder");
- return sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0;
- }))
+ //now we can check the non-volatile flag
+ if (_allAvailableTrees != null)
{
- var applicationAlias = (string) addElement.Attribute("application");
- var type = (string) addElement.Attribute("type");
- var assembly = (string) addElement.Attribute("assembly");
+ var hasChanges = false;
- var clrType = Type.GetType(type);
- if (clrType == null)
+ LoadXml(doc =>
{
- LogHelper.Warn("The tree definition: " + addElement.ToString() + " could not be resolved to a .Net object type");
- continue;
- }
+ //Now, load in the xml structure and update it with anything that is not declared there and save the file.
- //check if the tree definition (applicationAlias + type + assembly) is already in the list
+ //NOTE: On the first iteration here, it will lazily scan all trees, etc... this is because this ienumerable is lazy
+ // based on the ApplicationTreeRegistrar - and as noted there this is not an ideal way to do things but were stuck like this
+ // currently because of the legacy assemblies and types not in the Core.
- if (list.Any(tree => tree.ApplicationAlias.InvariantEquals(applicationAlias) && tree.GetRuntimeType() == clrType) == false)
+ //Get all the trees not registered in the config
+ var unregistered = _allAvailableTrees
+ .Where(x => list.Any(l => l.Alias == x.Alias) == false)
+ .ToArray();
+
+ hasChanges = unregistered.Any();
+
+ if (hasChanges == false) return false;
+
+ //add the unregistered ones to the list and re-save the file if any changes were found
+ var count = 0;
+ foreach (var tree in unregistered)
+ {
+ doc.Root.Add(new XElement("add",
+ new XAttribute("initialize", tree.Initialize),
+ new XAttribute("sortOrder", tree.SortOrder),
+ new XAttribute("alias", tree.Alias),
+ new XAttribute("application", tree.ApplicationAlias),
+ new XAttribute("title", tree.Title),
+ new XAttribute("iconClosed", tree.IconClosed),
+ new XAttribute("iconOpen", tree.IconOpened),
+ new XAttribute("type", tree.Type)));
+ count++;
+ }
+
+ //don't save if there's no changes
+ return count > 0;
+ }, true);
+
+ if (hasChanges)
{
- list.Add(new ApplicationTree(
- addElement.Attribute("initialize") == null || Convert.ToBoolean(addElement.Attribute("initialize").Value),
- addElement.Attribute("sortOrder") != null ? Convert.ToByte(addElement.Attribute("sortOrder").Value) : (byte) 0,
- addElement.Attribute("application").Value,
- addElement.Attribute("alias").Value,
- addElement.Attribute("title").Value,
- addElement.Attribute("iconClosed").Value,
- addElement.Attribute("iconOpen").Value,
- addElement.Attribute("type").Value));
+ //If there were changes, we need to re-read the structures from the XML
+ list = ReadFromXmlAndSort();
}
}
- }, false);
- return list;
- });
+ _isInitialized = true;
+ }
+ }
+ }
+
+
+ return list;
+
+
+ });
}
- public void Intitialize(IEnumerable existingTrees)
+ ///
+ /// Initializes the service with any trees found in plugins
+ ///
+ ///
+ /// A collection of all available tree found in assemblies in the application
+ ///
+ ///
+ /// This will update the trees.config with the found tree plugins that are not currently listed in the file when the first
+ /// access is made to resolve the tree collection
+ ///
+ public void Intitialize(IEnumerable allAvailableTrees)
{
- LoadXml(doc =>
- {
- foreach (var tree in existingTrees)
- {
- doc.Root.Add(new XElement("add",
- new XAttribute("initialize", tree.Initialize),
- new XAttribute("sortOrder", tree.SortOrder),
- new XAttribute("alias", tree.Alias),
- new XAttribute("application", tree.ApplicationAlias),
- new XAttribute("title", tree.Title),
- new XAttribute("iconClosed", tree.IconClosed),
- new XAttribute("iconOpen", tree.IconOpened),
- new XAttribute("type", tree.Type)));
- }
-
- }, true);
+ _allAvailableTrees = allAvailableTrees;
}
///
@@ -134,16 +165,19 @@ namespace Umbraco.Core.Services
if (el == null)
{
- doc.Root.Add(new XElement("add",
- new XAttribute("initialize", initialize),
- new XAttribute("sortOrder", sortOrder),
- new XAttribute("alias", alias),
- new XAttribute("application", applicationAlias),
- new XAttribute("title", title),
- new XAttribute("iconClosed", iconClosed),
- new XAttribute("iconOpen", iconOpened),
- new XAttribute("type", type)));
+ doc.Root.Add(new XElement("add",
+ new XAttribute("initialize", initialize),
+ new XAttribute("sortOrder", sortOrder),
+ new XAttribute("alias", alias),
+ new XAttribute("application", applicationAlias),
+ new XAttribute("title", title),
+ new XAttribute("iconClosed", iconClosed),
+ new XAttribute("iconOpen", iconOpened),
+ new XAttribute("type", type)));
}
+
+ return true;
+
}, true);
OnNew(new ApplicationTree(initialize, sortOrder, applicationAlias, alias, title, iconClosed, iconOpened, type), new EventArgs());
@@ -161,7 +195,7 @@ namespace Umbraco.Core.Services
if (el != null)
{
el.RemoveAttributes();
-
+
el.Add(new XAttribute("initialize", tree.Initialize));
el.Add(new XAttribute("sortOrder", tree.SortOrder));
el.Add(new XAttribute("alias", tree.Alias));
@@ -172,6 +206,8 @@ namespace Umbraco.Core.Services
el.Add(new XAttribute("type", tree.Type));
}
+ return true;
+
}, true);
OnUpdated(tree, new EventArgs());
@@ -181,11 +217,16 @@ namespace Umbraco.Core.Services
/// Deletes this instance.
///
public void DeleteTree(ApplicationTree tree)
- {
+ {
LoadXml(doc =>
{
- doc.Root.Elements("add").Where(x => x.Attribute("application") != null && x.Attribute("application").Value == tree.ApplicationAlias &&
- x.Attribute("alias") != null && x.Attribute("alias").Value == tree.Alias).Remove();
+ doc.Root.Elements("add")
+ .Where(x => x.Attribute("application") != null
+ && x.Attribute("application").Value == tree.ApplicationAlias
+ && x.Attribute("alias") != null && x.Attribute("alias").Value == tree.Alias).Remove();
+
+ return true;
+
}, true);
OnDeleted(tree, new EventArgs());
@@ -231,31 +272,44 @@ namespace Umbraco.Core.Services
{
var list = GetAppTrees().FindAll(
t =>
- {
- if (onlyInitialized)
- return (t.ApplicationAlias == applicationAlias && t.Initialize);
- return (t.ApplicationAlias == applicationAlias);
- }
+ {
+ if (onlyInitialized)
+ return (t.ApplicationAlias == applicationAlias && t.Initialize);
+ return (t.ApplicationAlias == applicationAlias);
+ }
);
return list.OrderBy(x => x.SortOrder).ToArray();
}
- internal void LoadXml(Action callback, bool saveAfterCallback)
+ ///
+ /// Loads in the xml structure from disk if one is found, otherwise loads in an empty xml structure, calls the
+ /// callback with the xml document and saves the structure back to disk if saveAfterCallback is true.
+ ///
+ ///
+ ///
+ internal void LoadXml(Func callback, bool saveAfterCallbackIfChanges)
{
lock (Locker)
{
var doc = File.Exists(TreeConfigFilePath)
? XDocument.Load(TreeConfigFilePath)
: XDocument.Parse("");
+
if (doc.Root != null)
{
- callback.Invoke(doc);
+ var hasChanges = callback.Invoke(doc);
- if (saveAfterCallback)
+ if (saveAfterCallbackIfChanges && hasChanges
+ //Don't save it if it is empty, in some very rare cases if the app domain get's killed in the middle of this process
+ // in some insane way the file saved will be empty. I'm pretty sure it's not actually anything to do with the xml doc and
+ // more about the IO trying to save the XML doc, but it doesn't hurt to check.
+ && doc.Root != null && doc.Root.Elements().Any())
{
+ //ensures the folder exists
Directory.CreateDirectory(Path.GetDirectoryName(TreeConfigFilePath));
+ //saves it
doc.Save(TreeConfigFilePath);
//remove the cache now that it has changed SD: I'm leaving this here even though it
@@ -266,6 +320,54 @@ namespace Umbraco.Core.Services
}
}
+ private List ReadFromXmlAndSort()
+ {
+ var list = new List();
+
+ //read in the xml file containing trees and convert them all to ApplicationTree instances
+ LoadXml(doc =>
+ {
+ foreach (var addElement in doc.Root.Elements("add").OrderBy(x =>
+ {
+ var sortOrderAttr = x.Attribute("sortOrder");
+ return sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0;
+ }))
+ {
+ var applicationAlias = (string)addElement.Attribute("application");
+ var type = (string)addElement.Attribute("type");
+ var assembly = (string)addElement.Attribute("assembly");
+
+ var clrType = Type.GetType(type);
+ if (clrType == null)
+ {
+ LogHelper.Warn("The tree definition: " + addElement.ToString() + " could not be resolved to a .Net object type");
+ continue;
+ }
+
+ //check if the tree definition (applicationAlias + type + assembly) is already in the list
+
+ if (list.Any(tree => tree.ApplicationAlias.InvariantEquals(applicationAlias) && tree.GetRuntimeType() == clrType) == false)
+ {
+ list.Add(new ApplicationTree(
+ addElement.Attribute("initialize") == null || Convert.ToBoolean(addElement.Attribute("initialize").Value),
+ addElement.Attribute("sortOrder") != null ? Convert.ToByte(addElement.Attribute("sortOrder").Value) : (byte)0,
+ addElement.Attribute("application").Value,
+ addElement.Attribute("alias").Value,
+ addElement.Attribute("title").Value,
+ addElement.Attribute("iconClosed").Value,
+ addElement.Attribute("iconOpen").Value,
+ addElement.Attribute("type").Value));
+ }
+ }
+
+ return false;
+
+ }, false);
+
+ return list;
+ }
+
+
internal static event TypedEventHandler Deleted;
private static void OnDeleted(ApplicationTree app, EventArgs args)
{
diff --git a/src/Umbraco.Core/Services/IApplicationTreeService.cs b/src/Umbraco.Core/Services/IApplicationTreeService.cs
index c7aecec6fb..6a4d2bda33 100644
--- a/src/Umbraco.Core/Services/IApplicationTreeService.cs
+++ b/src/Umbraco.Core/Services/IApplicationTreeService.cs
@@ -5,7 +5,17 @@ namespace Umbraco.Core.Services
{
public interface IApplicationTreeService
{
- void Intitialize(IEnumerable existingTrees);
+ ///
+ /// Initializes the service with any trees found in plugins
+ ///
+ ///
+ /// A collection of all available tree found in assemblies in the application
+ ///
+ ///
+ /// This will update the trees.config with the found tree plugins that are not currently listed in the file when the first
+ /// access is made to resolve the tree collection
+ ///
+ void Intitialize(IEnumerable allAvailableTrees);
///
/// Creates a new application tree.
diff --git a/src/Umbraco.Core/Services/ISectionService.cs b/src/Umbraco.Core/Services/ISectionService.cs
index bc950b9470..df5c89d4bf 100644
--- a/src/Umbraco.Core/Services/ISectionService.cs
+++ b/src/Umbraco.Core/Services/ISectionService.cs
@@ -6,10 +6,15 @@ namespace Umbraco.Core.Services
public interface ISectionService
{
///
- /// Ensures all available sections exist in the storage medium
+ /// Initializes the service with all available application plugins
///
- ///
- void Initialize(IEnumerable existingSections);
+ ///
+ /// All application plugins found in assemblies
+ ///
+ ///
+ /// This is used to populate the app.config file with any applications declared in plugins that don't exist in the file
+ ///
+ void Initialize(IEnumerable allAvailableSections);
///
/// The cache storage for all applications
diff --git a/src/Umbraco.Core/Services/SectionService.cs b/src/Umbraco.Core/Services/SectionService.cs
index 00fa28e38c..1a3568cff3 100644
--- a/src/Umbraco.Core/Services/SectionService.cs
+++ b/src/Umbraco.Core/Services/SectionService.cs
@@ -17,12 +17,19 @@ namespace Umbraco.Core.Services
internal class SectionService : ISectionService
{
private readonly IUserService _userService;
+ private IEnumerable _allAvailableSections;
private readonly IApplicationTreeService _applicationTreeService;
+ private readonly IDatabaseUnitOfWorkProvider _uowProvider;
private readonly CacheHelper _cache;
+ internal const string AppConfigFileName = "applications.config";
+ private static string _appConfig;
+ private volatile bool _isInitialized = false;
+ private static readonly object Locker = new object();
public SectionService(
IUserService userService,
- IApplicationTreeService applicationTreeService,
+ IApplicationTreeService applicationTreeService,
+ IDatabaseUnitOfWorkProvider uowProvider,
CacheHelper cache)
{
if (applicationTreeService == null) throw new ArgumentNullException("applicationTreeService");
@@ -30,12 +37,11 @@ namespace Umbraco.Core.Services
_userService = userService;
_applicationTreeService = applicationTreeService;
+ _uowProvider = uowProvider;
_cache = cache;
}
- internal const string AppConfigFileName = "applications.config";
- private static string _appConfig;
- private static readonly object Locker = new object();
+
///
/// gets/sets the application.config file path
@@ -57,22 +63,17 @@ namespace Umbraco.Core.Services
}
///
- /// Ensures all available sections exist in the storage medium
+ /// Initializes the service with all available application plugins
///
- ///
- public void Initialize(IEnumerable existingSections)
+ ///
+ /// All application plugins found in assemblies
+ ///
+ ///
+ /// This is used to populate the app.config file with any applications declared in plugins that don't exist in the file
+ ///
+ public void Initialize(IEnumerable allAvailableSections)
{
- LoadXml(doc =>
- {
- foreach (var attr in existingSections)
- {
- doc.Root.Add(new XElement("add",
- new XAttribute("alias", attr.Alias),
- new XAttribute("name", attr.Name),
- new XAttribute("icon", attr.Icon),
- new XAttribute("sortOrder", attr.SortOrder)));
- }
- }, true);
+ _allAvailableSections = allAvailableSections;
}
///
@@ -80,7 +81,7 @@ namespace Umbraco.Core.Services
///
public IEnumerable GetSections()
{
- return _cache.GetCacheItem(
+ return _cache.RuntimeCache.GetCacheItem>(
CacheKeys.ApplicationsCacheKey,
() =>
{
@@ -88,28 +89,66 @@ namespace Umbraco.Core.Services
//if (_testApps != null)
// return _testApps;
- var tmp = new List();
+ var list = ReadFromXmlAndSort();
- LoadXml(doc =>
+ //On first access we need to do some initialization
+ if (_isInitialized == false)
+ {
+ lock (Locker)
{
- foreach (var addElement in doc.Root.Elements("add").OrderBy(x =>
- {
- var sortOrderAttr = x.Attribute("sortOrder");
- return sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0;
- }))
+ if (_isInitialized == false)
{
- var sortOrderAttr = addElement.Attribute("sortOrder");
- tmp.Add(new Section(addElement.Attribute("name").Value,
- addElement.Attribute("alias").Value,
- addElement.Attribute("icon").Value,
- sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0));
+ //now we can check the non-volatile flag
+ if (_allAvailableSections != null)
+ {
+ var hasChanges = false;
+
+ LoadXml(doc =>
+ {
+ //Now, load in the xml structure and update it with anything that is not declared there and save the file.
+
+ //NOTE: On the first iteration here, it will lazily scan all apps, etc... this is because this ienumerable is lazy
+ // based on the ApplicationRegistrar - and as noted there this is not an ideal way to do things but were stuck like this
+ // currently because of the legacy assemblies and types not in the Core.
+
+ //Get all the trees not registered in the config
+ var unregistered = _allAvailableSections
+ .Where(x => list.Any(l => l.Alias == x.Alias) == false)
+ .ToArray();
+
+ hasChanges = unregistered.Any();
+
+ var count = 0;
+ foreach (var attr in unregistered)
+ {
+ doc.Root.Add(new XElement("add",
+ new XAttribute("alias", attr.Alias),
+ new XAttribute("name", attr.Name),
+ new XAttribute("icon", attr.Icon),
+ new XAttribute("sortOrder", attr.SortOrder)));
+ count++;
+ }
+
+ //don't save if there's no changes
+ return count > 0;
+ }, true);
+
+ if (hasChanges)
+ {
+ //If there were changes, we need to re-read the structures from the XML
+ list = ReadFromXmlAndSort();
+ }
+ }
}
- }, false);
- return tmp;
+ }
+ }
+
+ return list;
+
});
}
- internal void LoadXml(Action callback, bool saveAfterCallback)
+ internal void LoadXml(Func callback, bool saveAfterCallbackIfChanged)
{
lock (Locker)
{
@@ -119,9 +158,9 @@ namespace Umbraco.Core.Services
if (doc.Root != null)
{
- callback.Invoke(doc);
+ var changed = callback.Invoke(doc);
- if (saveAfterCallback)
+ if (saveAfterCallbackIfChanged && changed)
{
//ensure the folder is created!
Directory.CreateDirectory(Path.GetDirectoryName(AppConfigFilePath));
@@ -194,6 +233,7 @@ namespace Umbraco.Core.Services
new XAttribute("name", name),
new XAttribute("icon", icon),
new XAttribute("sortOrder", sortOrder)));
+ return true;
}, true);
//raise event
@@ -209,7 +249,7 @@ namespace Umbraco.Core.Services
lock (Locker)
{
//delete the assigned applications
- ApplicationContext.Current.DatabaseContext.Database.Execute(
+ _uowProvider.GetUnitOfWork().Database.Execute(
"delete from umbracoUser2App where app = @appAlias",
new { appAlias = section.Alias });
@@ -222,7 +262,10 @@ namespace Umbraco.Core.Services
LoadXml(doc =>
{
- doc.Root.Elements("add").Where(x => x.Attribute("alias") != null && x.Attribute("alias").Value == section.Alias).Remove();
+ doc.Root.Elements("add").Where(x => x.Attribute("alias") != null && x.Attribute("alias").Value == section.Alias)
+ .Remove();
+
+ return true;
}, true);
//raise event
@@ -230,6 +273,30 @@ namespace Umbraco.Core.Services
}
}
+ private List ReadFromXmlAndSort()
+ {
+ var tmp = new List();
+
+ LoadXml(doc =>
+ {
+ foreach (var addElement in doc.Root.Elements("add").OrderBy(x =>
+ {
+ var sortOrderAttr = x.Attribute("sortOrder");
+ return sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0;
+ }))
+ {
+ var sortOrderAttr = addElement.Attribute("sortOrder");
+ tmp.Add(new Section(addElement.Attribute("name").Value,
+ addElement.Attribute("alias").Value,
+ addElement.Attribute("icon").Value,
+ sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0));
+ }
+ return false;
+ }, false);
+
+ return tmp;
+ }
+
internal static event TypedEventHandler Deleted;
private static void OnDeleted(Section app, EventArgs args)
{
diff --git a/src/Umbraco.Core/Services/ServiceContext.cs b/src/Umbraco.Core/Services/ServiceContext.cs
index afc44a3359..79280b371f 100644
--- a/src/Umbraco.Core/Services/ServiceContext.cs
+++ b/src/Umbraco.Core/Services/ServiceContext.cs
@@ -164,7 +164,7 @@ namespace Umbraco.Core.Services
_treeService = new Lazy(() => new ApplicationTreeService(cache));
if (_sectionService == null)
- _sectionService = new Lazy(() => new SectionService(_userService.Value, _treeService.Value, cache));
+ _sectionService = new Lazy(() => new SectionService(_userService.Value, _treeService.Value, provider, cache));
if (_macroService == null)
_macroService = new Lazy(() => new MacroService(provider, repositoryFactory.Value));
diff --git a/src/Umbraco.Core/Sync/ServerEnvironmentHelper.cs b/src/Umbraco.Core/Sync/ServerEnvironmentHelper.cs
index 63e5fbc553..52480a1ca7 100644
--- a/src/Umbraco.Core/Sync/ServerEnvironmentHelper.cs
+++ b/src/Umbraco.Core/Sync/ServerEnvironmentHelper.cs
@@ -3,6 +3,7 @@ using System.Linq;
using System.Web;
using System.Xml;
using Umbraco.Core.Configuration;
+using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
namespace Umbraco.Core.Sync
@@ -19,28 +20,24 @@ namespace Umbraco.Core.Sync
///
/// The full base url including schema (i.e. http://myserver:80/umbraco ) - or null if the url
/// cannot be determined at the moment (usually because the first request has not properly completed yet).
- public static string GetCurrentServerUmbracoBaseUrl()
+ public static string GetCurrentServerUmbracoBaseUrl(ApplicationContext appContext, IUmbracoSettingsSection settings)
{
- var status = GetStatus();
+ var status = GetStatus(settings);
if (status == CurrentServerEnvironmentStatus.Single)
{
- // single install, return null if no original url, else use original url as base
+ // single install, return null if no config/original url, else use config/original url as base
// use http or https as appropriate
- return string.IsNullOrWhiteSpace(ApplicationContext.Current.OriginalRequestUrl)
- ? null // not initialized yet
- : string.Format("http{0}://{1}", GlobalSettings.UseSSL ? "s" : "", ApplicationContext.Current.OriginalRequestUrl);
+ return GetBaseUrl(appContext, settings);
}
- var servers = UmbracoConfig.For.UmbracoSettings().DistributedCall.Servers.ToArray();
+ var servers = settings.DistributedCall.Servers.ToArray();
if (servers.Any() == false)
{
- // cannot be determined, return null if no original url, else use original url as base
+ // cannot be determined, return null if no config/original url, else use config/original url as base
// use http or https as appropriate
- return string.IsNullOrWhiteSpace(ApplicationContext.Current.OriginalRequestUrl)
- ? null // not initialized yet
- : string.Format("http{0}://{1}", GlobalSettings.UseSSL ? "s" : "", ApplicationContext.Current.OriginalRequestUrl);
+ return GetBaseUrl(appContext, settings);
}
foreach (var server in servers)
@@ -65,25 +62,23 @@ namespace Umbraco.Core.Sync
}
}
- // cannot be determined, return null if no original url, else use original url as base
+ // cannot be determined, return null if no config/original url, else use config/original url as base
// use http or https as appropriate
- return string.IsNullOrWhiteSpace(ApplicationContext.Current.OriginalRequestUrl)
- ? null // not initialized yet
- : string.Format("http{0}://{1}", GlobalSettings.UseSSL ? "s" : "", ApplicationContext.Current.OriginalRequestUrl);
+ return GetBaseUrl(appContext, settings);
}
///
/// Returns the current environment status for the current server
///
///
- public static CurrentServerEnvironmentStatus GetStatus()
+ public static CurrentServerEnvironmentStatus GetStatus(IUmbracoSettingsSection settings)
{
- if (UmbracoConfig.For.UmbracoSettings().DistributedCall.Enabled == false)
+ if (settings.DistributedCall.Enabled == false)
{
return CurrentServerEnvironmentStatus.Single;
}
- var servers = UmbracoConfig.For.UmbracoSettings().DistributedCall.Servers.ToArray();
+ var servers = settings.DistributedCall.Servers.ToArray();
if (servers.Any() == false)
{
@@ -118,5 +113,21 @@ namespace Umbraco.Core.Sync
return CurrentServerEnvironmentStatus.Slave;
}
+
+ private static string GetBaseUrl(ApplicationContext appContext, IUmbracoSettingsSection settings)
+ {
+ return (
+ // is config empty?
+ settings.ScheduledTasks.BaseUrl.IsNullOrWhiteSpace()
+ // is the orig req empty?
+ ? appContext.OriginalRequestUrl.IsNullOrWhiteSpace()
+ // we've got nothing
+ ? null
+ //the orig req url is not null, use that
+ : string.Format("http{0}://{1}", GlobalSettings.UseSSL ? "s" : "", appContext.OriginalRequestUrl)
+ // the config has been specified, use that
+ : string.Format("http{0}://{1}", GlobalSettings.UseSSL ? "s" : "", settings.ScheduledTasks.BaseUrl))
+ .EnsureEndsWith('/');
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/GlobalSettingsTests.cs b/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs
similarity index 95%
rename from src/Umbraco.Tests/GlobalSettingsTests.cs
rename to src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs
index 7f97466bae..b320c979ef 100644
--- a/src/Umbraco.Tests/GlobalSettingsTests.cs
+++ b/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs
@@ -1,120 +1,119 @@
-using System.Configuration;
-using System.Web.Routing;
-using NUnit.Framework;
-using Umbraco.Core.Configuration;
-using Umbraco.Core.IO;
-using Umbraco.Tests.TestHelpers;
-using System.Web.Mvc;
-
-namespace Umbraco.Tests
-{
- [TestFixture]
- public class GlobalSettingsTests : BaseWebTest
- {
-
- public override void Initialize()
- {
- base.Initialize();
- SettingsForTests.UmbracoPath = "~/umbraco";
- }
-
- public override void TearDown()
- {
- //ensure this is reset
- SystemDirectories.Root = null;
- SettingsForTests.UmbracoPath = "~/umbraco";
- //reset the app config
- base.TearDown();
-
- }
-
- [Test]
- public void Is_Debug_Mode()
- {
- Assert.That(Umbraco.Core.Configuration.GlobalSettings.DebugMode, Is.EqualTo(true));
- }
-
- [Ignore]
- [Test]
- public void Is_Version_From_Assembly_Correct()
- {
- Assert.That(UmbracoVersion.Current.ToString(3), Is.EqualTo("6.0.0"));
- }
-
- [TestCase("~/umbraco", "/", "umbraco")]
- [TestCase("~/umbraco", "/MyVirtualDir", "umbraco")]
- [TestCase("~/customPath", "/MyVirtualDir/", "custompath")]
- [TestCase("~/some-wacky/nestedPath", "/MyVirtualDir", "some-wacky-nestedpath")]
- [TestCase("~/some-wacky/nestedPath", "/MyVirtualDir/NestedVDir/", "some-wacky-nestedpath")]
- public void Umbraco_Mvc_Area(string path, string rootPath, string outcome)
- {
- SettingsForTests.UmbracoPath = path;
- SystemDirectories.Root = rootPath;
- Assert.AreEqual(outcome, Umbraco.Core.Configuration.GlobalSettings.UmbracoMvcArea);
- }
-
- [TestCase("/umbraco/umbraco.aspx")]
- [TestCase("/umbraco/editContent.aspx")]
- [TestCase("/install/default.aspx")]
- [TestCase("/install/")]
- [TestCase("/install")]
- [TestCase("/install/?installStep=asdf")]
- [TestCase("/install/test.aspx")]
- [TestCase("/config/splashes/booting.aspx")]
- public void Is_Reserved_Path_Or_Url(string url)
- {
- Assert.IsTrue(Umbraco.Core.Configuration.GlobalSettings.IsReservedPathOrUrl(url));
- }
-
- [TestCase("/umbraco_client/Tree/treeIcons.css")]
- [TestCase("/umbraco_client/Tree/Themes/umbraco/style.css")]
- [TestCase("/umbraco_client/scrollingmenu/style.css")]
- [TestCase("/base/somebasehandler")]
- [TestCase("/")]
- [TestCase("/home.aspx")]
- [TestCase("/umbraco-test")]
- [TestCase("/install-test")]
- [TestCase("/install.aspx")]
- public void Is_Not_Reserved_Path_Or_Url(string url)
- {
- Assert.IsFalse(Umbraco.Core.Configuration.GlobalSettings.IsReservedPathOrUrl(url));
- }
-
-
- [TestCase("/Do/Not/match", false)]
- [TestCase("/Umbraco/RenderMvcs", false)]
- [TestCase("/Umbraco/RenderMvc", true)]
- [TestCase("/Umbraco/RenderMvc/Index", true)]
- [TestCase("/Umbraco/RenderMvc/Index/1234", true)]
- [TestCase("/Umbraco/RenderMvc/Index/1234/9876", false)]
- [TestCase("/api", true)]
- [TestCase("/api/WebApiTest", true)]
- [TestCase("/api/WebApiTest/1234", true)]
- [TestCase("/api/WebApiTest/Index/1234", false)]
- public void Is_Reserved_By_Route(string url, bool shouldMatch)
- {
- //reset the app config, we only want to test routes not the hard coded paths
- Umbraco.Core.Configuration.GlobalSettings.ReservedPaths = "";
- Umbraco.Core.Configuration.GlobalSettings.ReservedUrls = "";
-
- var routes = new RouteCollection();
-
- routes.MapRoute(
- "Umbraco_default",
- "Umbraco/RenderMvc/{action}/{id}",
- new { controller = "RenderMvc", action = "Index", id = UrlParameter.Optional });
- routes.MapRoute(
- "WebAPI",
- "api/{controller}/{id}",
- new { controller = "WebApiTestController", action = "Index", id = UrlParameter.Optional });
-
-
- var context = new FakeHttpContextFactory(url);
-
-
- Assert.AreEqual(
- shouldMatch,
- Umbraco.Core.Configuration.GlobalSettings.IsReservedPathOrUrl(url, context.HttpContext, routes));
- }
- }
+using System.Web.Mvc;
+using System.Web.Routing;
+using NUnit.Framework;
+using Umbraco.Core.Configuration;
+using Umbraco.Core.IO;
+using Umbraco.Tests.TestHelpers;
+
+namespace Umbraco.Tests.Configurations
+{
+ [TestFixture]
+ public class GlobalSettingsTests : BaseWebTest
+ {
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SettingsForTests.UmbracoPath = "~/umbraco";
+ }
+
+ public override void TearDown()
+ {
+ //ensure this is reset
+ SystemDirectories.Root = null;
+ SettingsForTests.UmbracoPath = "~/umbraco";
+ //reset the app config
+ base.TearDown();
+
+ }
+
+ [Test]
+ public void Is_Debug_Mode()
+ {
+ Assert.That(Umbraco.Core.Configuration.GlobalSettings.DebugMode, Is.EqualTo(true));
+ }
+
+ [Ignore]
+ [Test]
+ public void Is_Version_From_Assembly_Correct()
+ {
+ Assert.That(UmbracoVersion.Current.ToString(3), Is.EqualTo("6.0.0"));
+ }
+
+ [TestCase("~/umbraco", "/", "umbraco")]
+ [TestCase("~/umbraco", "/MyVirtualDir", "umbraco")]
+ [TestCase("~/customPath", "/MyVirtualDir/", "custompath")]
+ [TestCase("~/some-wacky/nestedPath", "/MyVirtualDir", "some-wacky-nestedpath")]
+ [TestCase("~/some-wacky/nestedPath", "/MyVirtualDir/NestedVDir/", "some-wacky-nestedpath")]
+ public void Umbraco_Mvc_Area(string path, string rootPath, string outcome)
+ {
+ SettingsForTests.UmbracoPath = path;
+ SystemDirectories.Root = rootPath;
+ Assert.AreEqual(outcome, Umbraco.Core.Configuration.GlobalSettings.UmbracoMvcArea);
+ }
+
+ [TestCase("/umbraco/umbraco.aspx")]
+ [TestCase("/umbraco/editContent.aspx")]
+ [TestCase("/install/default.aspx")]
+ [TestCase("/install/")]
+ [TestCase("/install")]
+ [TestCase("/install/?installStep=asdf")]
+ [TestCase("/install/test.aspx")]
+ [TestCase("/config/splashes/booting.aspx")]
+ public void Is_Reserved_Path_Or_Url(string url)
+ {
+ Assert.IsTrue(Umbraco.Core.Configuration.GlobalSettings.IsReservedPathOrUrl(url));
+ }
+
+ [TestCase("/umbraco_client/Tree/treeIcons.css")]
+ [TestCase("/umbraco_client/Tree/Themes/umbraco/style.css")]
+ [TestCase("/umbraco_client/scrollingmenu/style.css")]
+ [TestCase("/base/somebasehandler")]
+ [TestCase("/")]
+ [TestCase("/home.aspx")]
+ [TestCase("/umbraco-test")]
+ [TestCase("/install-test")]
+ [TestCase("/install.aspx")]
+ public void Is_Not_Reserved_Path_Or_Url(string url)
+ {
+ Assert.IsFalse(Umbraco.Core.Configuration.GlobalSettings.IsReservedPathOrUrl(url));
+ }
+
+
+ [TestCase("/Do/Not/match", false)]
+ [TestCase("/Umbraco/RenderMvcs", false)]
+ [TestCase("/Umbraco/RenderMvc", true)]
+ [TestCase("/Umbraco/RenderMvc/Index", true)]
+ [TestCase("/Umbraco/RenderMvc/Index/1234", true)]
+ [TestCase("/Umbraco/RenderMvc/Index/1234/9876", false)]
+ [TestCase("/api", true)]
+ [TestCase("/api/WebApiTest", true)]
+ [TestCase("/api/WebApiTest/1234", true)]
+ [TestCase("/api/WebApiTest/Index/1234", false)]
+ public void Is_Reserved_By_Route(string url, bool shouldMatch)
+ {
+ //reset the app config, we only want to test routes not the hard coded paths
+ Umbraco.Core.Configuration.GlobalSettings.ReservedPaths = "";
+ Umbraco.Core.Configuration.GlobalSettings.ReservedUrls = "";
+
+ var routes = new RouteCollection();
+
+ routes.MapRoute(
+ "Umbraco_default",
+ "Umbraco/RenderMvc/{action}/{id}",
+ new { controller = "RenderMvc", action = "Index", id = UrlParameter.Optional });
+ routes.MapRoute(
+ "WebAPI",
+ "api/{controller}/{id}",
+ new { controller = "WebApiTestController", action = "Index", id = UrlParameter.Optional });
+
+
+ var context = new FakeHttpContextFactory(url);
+
+
+ Assert.AreEqual(
+ shouldMatch,
+ Umbraco.Core.Configuration.GlobalSettings.IsReservedPathOrUrl(url, context.HttpContext, routes));
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/Surface/PluginControllerAreaTests.cs b/src/Umbraco.Tests/Controllers/PluginControllerAreaTests.cs
similarity index 92%
rename from src/Umbraco.Tests/Surface/PluginControllerAreaTests.cs
rename to src/Umbraco.Tests/Controllers/PluginControllerAreaTests.cs
index 2ed7bf9876..a2ad7220a5 100644
--- a/src/Umbraco.Tests/Surface/PluginControllerAreaTests.cs
+++ b/src/Umbraco.Tests/Controllers/PluginControllerAreaTests.cs
@@ -1,90 +1,87 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using NUnit.Framework;
-using Umbraco.Tests.TestHelpers;
-using Umbraco.Web;
-using Umbraco.Web.Mvc;
-
-namespace Umbraco.Tests.Surface
-{
- [TestFixture]
- public class PluginControllerAreaTests : BaseWebTest
- {
-
- [Test]
- public void Ensure_Same_Area1()
- {
- Assert.Throws(() =>
- new PluginControllerArea(new PluginControllerMetadata[]
- {
- PluginController.GetMetadata(typeof(Plugin1Controller)),
- PluginController.GetMetadata(typeof(Plugin2Controller)),
- PluginController.GetMetadata(typeof(Plugin3Controller)) //not same area
- }));
- }
-
- [Test]
- public void Ensure_Same_Area3()
- {
- Assert.Throws(() =>
- new PluginControllerArea(new PluginControllerMetadata[]
- {
- PluginController.GetMetadata(typeof(Plugin1Controller)),
- PluginController.GetMetadata(typeof(Plugin2Controller)),
- PluginController.GetMetadata(typeof(Plugin4Controller)) //no area assigned
- }));
- }
-
- [Test]
- public void Ensure_Same_Area2()
- {
- var area = new PluginControllerArea(new PluginControllerMetadata[]
- {
- PluginController.GetMetadata(typeof(Plugin1Controller)),
- PluginController.GetMetadata(typeof(Plugin2Controller))
- });
- Assert.Pass();
- }
-
- #region Test classes
-
- [PluginController("Area1")]
- public class Plugin1Controller : PluginController
- {
- public Plugin1Controller(UmbracoContext umbracoContext) : base(umbracoContext)
- {
- }
- }
-
- [PluginController("Area1")]
- public class Plugin2Controller : PluginController
- {
- public Plugin2Controller(UmbracoContext umbracoContext)
- : base(umbracoContext)
- {
- }
- }
-
- [PluginController("Area2")]
- public class Plugin3Controller : PluginController
- {
- public Plugin3Controller(UmbracoContext umbracoContext)
- : base(umbracoContext)
- {
- }
- }
-
- public class Plugin4Controller : PluginController
- {
- public Plugin4Controller(UmbracoContext umbracoContext)
- : base(umbracoContext)
- {
- }
- }
-
- #endregion
-
- }
-}
+using System;
+using NUnit.Framework;
+using Umbraco.Tests.TestHelpers;
+using Umbraco.Web;
+using Umbraco.Web.Mvc;
+
+namespace Umbraco.Tests.Controllers
+{
+ [TestFixture]
+ public class PluginControllerAreaTests : BaseWebTest
+ {
+
+ [Test]
+ public void Ensure_Same_Area1()
+ {
+ Assert.Throws(() =>
+ new PluginControllerArea(new PluginControllerMetadata[]
+ {
+ PluginController.GetMetadata(typeof(Plugin1Controller)),
+ PluginController.GetMetadata(typeof(Plugin2Controller)),
+ PluginController.GetMetadata(typeof(Plugin3Controller)) //not same area
+ }));
+ }
+
+ [Test]
+ public void Ensure_Same_Area3()
+ {
+ Assert.Throws(() =>
+ new PluginControllerArea(new PluginControllerMetadata[]
+ {
+ PluginController.GetMetadata(typeof(Plugin1Controller)),
+ PluginController.GetMetadata(typeof(Plugin2Controller)),
+ PluginController.GetMetadata(typeof(Plugin4Controller)) //no area assigned
+ }));
+ }
+
+ [Test]
+ public void Ensure_Same_Area2()
+ {
+ var area = new PluginControllerArea(new PluginControllerMetadata[]
+ {
+ PluginController.GetMetadata(typeof(Plugin1Controller)),
+ PluginController.GetMetadata(typeof(Plugin2Controller))
+ });
+ Assert.Pass();
+ }
+
+ #region Test classes
+
+ [PluginController("Area1")]
+ public class Plugin1Controller : PluginController
+ {
+ public Plugin1Controller(UmbracoContext umbracoContext) : base(umbracoContext)
+ {
+ }
+ }
+
+ [PluginController("Area1")]
+ public class Plugin2Controller : PluginController
+ {
+ public Plugin2Controller(UmbracoContext umbracoContext)
+ : base(umbracoContext)
+ {
+ }
+ }
+
+ [PluginController("Area2")]
+ public class Plugin3Controller : PluginController
+ {
+ public Plugin3Controller(UmbracoContext umbracoContext)
+ : base(umbracoContext)
+ {
+ }
+ }
+
+ public class Plugin4Controller : PluginController
+ {
+ public Plugin4Controller(UmbracoContext umbracoContext)
+ : base(umbracoContext)
+ {
+ }
+ }
+
+ #endregion
+
+ }
+}
diff --git a/src/Umbraco.Tests/Sync/DistributedCacheTests.cs b/src/Umbraco.Tests/DistributedCache/DistributedCacheTests.cs
similarity index 89%
rename from src/Umbraco.Tests/Sync/DistributedCacheTests.cs
rename to src/Umbraco.Tests/DistributedCache/DistributedCacheTests.cs
index a897f59dae..c714cd0a2e 100644
--- a/src/Umbraco.Tests/Sync/DistributedCacheTests.cs
+++ b/src/Umbraco.Tests/DistributedCache/DistributedCacheTests.cs
@@ -1,211 +1,210 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using NUnit.Framework;
-using Umbraco.Core;
-using Umbraco.Core.ObjectResolution;
-using Umbraco.Core.Sync;
-using Umbraco.Web.Cache;
-using umbraco.interfaces;
-
-namespace Umbraco.Tests.Sync
-{
- ///
- /// Ensures that calls to DistributedCache methods carry through to the IServerMessenger correctly
- ///
- [TestFixture]
- public class DistributedCacheTests
- {
- [SetUp]
- public void Setup()
- {
- ServerRegistrarResolver.Current = new ServerRegistrarResolver(
- new TestServerRegistrar());
- ServerMessengerResolver.Current = new ServerMessengerResolver(
- new TestServerMessenger());
- CacheRefreshersResolver.Current = new CacheRefreshersResolver(() => new[] { typeof(TestCacheRefresher) });
- Resolution.Freeze();
- }
-
- [TearDown]
- public void Teardown()
- {
- ServerRegistrarResolver.Reset();
- ServerMessengerResolver.Reset();
- CacheRefreshersResolver.Reset();
- }
-
- [Test]
- public void RefreshIntId()
- {
- for (var i = 1; i < 11; i++)
- {
- DistributedCache.Instance.Refresh(Guid.Parse("E0F452CB-DCB2-4E84-B5A5-4F01744C5C73"), i);
- }
- Assert.AreEqual(10, ((TestServerMessenger)ServerMessengerResolver.Current.Messenger).IntIdsRefreshed.Count);
- }
-
- [Test]
- public void RefreshIntIdFromObject()
- {
- for (var i = 0; i < 10; i++)
- {
- DistributedCache.Instance.Refresh(
- Guid.Parse("E0F452CB-DCB2-4E84-B5A5-4F01744C5C73"),
- x => x.Id,
- new TestObjectWithId{Id = i});
- }
- Assert.AreEqual(10, ((TestServerMessenger)ServerMessengerResolver.Current.Messenger).IntIdsRefreshed.Count);
- }
-
- [Test]
- public void RefreshGuidId()
- {
- for (var i = 0; i < 11; i++)
- {
- DistributedCache.Instance.Refresh(Guid.Parse("E0F452CB-DCB2-4E84-B5A5-4F01744C5C73"), Guid.NewGuid());
- }
- Assert.AreEqual(11, ((TestServerMessenger)ServerMessengerResolver.Current.Messenger).GuidIdsRefreshed.Count);
- }
-
- [Test]
- public void RemoveIds()
- {
- for (var i = 1; i < 13; i++)
- {
- DistributedCache.Instance.Remove(Guid.Parse("E0F452CB-DCB2-4E84-B5A5-4F01744C5C73"), i);
- }
- Assert.AreEqual(12, ((TestServerMessenger)ServerMessengerResolver.Current.Messenger).IntIdsRemoved.Count);
- }
-
- [Test]
- public void FullRefreshes()
- {
- for (var i = 0; i < 13; i++)
- {
- DistributedCache.Instance.RefreshAll(Guid.Parse("E0F452CB-DCB2-4E84-B5A5-4F01744C5C73"));
- }
- Assert.AreEqual(13, ((TestServerMessenger)ServerMessengerResolver.Current.Messenger).CountOfFullRefreshes);
- }
-
- #region internal test classes
-
- internal class TestObjectWithId
- {
- public int Id { get; set; }
- }
-
- internal class TestCacheRefresher : ICacheRefresher
- {
- public Guid UniqueIdentifier
- {
- get { return Guid.Parse("E0F452CB-DCB2-4E84-B5A5-4F01744C5C73"); }
- }
- public string Name
- {
- get { return "Test"; }
- }
- public void RefreshAll()
- {
-
- }
-
- public void Refresh(int id)
- {
-
- }
-
- public void Remove(int id)
- {
-
- }
-
- public void Refresh(Guid id)
- {
-
- }
- }
-
- internal class TestServerMessenger : IServerMessenger
- {
- //used for tests
- public List IntIdsRefreshed = new List();
- public List GuidIdsRefreshed = new List();
- public List IntIdsRemoved = new List();
- public List PayloadsRemoved = new List();
- public List PayloadsRefreshed = new List();
- public int CountOfFullRefreshes = 0;
-
-
- public void PerformRefresh(IEnumerable servers, ICacheRefresher refresher, string jsonPayload)
- {
- PayloadsRefreshed.Add(jsonPayload);
- }
-
- public void PerformRefresh(IEnumerable servers, ICacheRefresher refresher, Func getNumericId, params T[] instances)
- {
- IntIdsRefreshed.AddRange(instances.Select(getNumericId));
- }
-
- public void PerformRefresh(IEnumerable servers, ICacheRefresher refresher, Func getGuidId, params T[] instances)
- {
- GuidIdsRefreshed.AddRange(instances.Select(getGuidId));
- }
-
- public void PerformRemove(IEnumerable servers, ICacheRefresher refresher, string jsonPayload)
- {
- PayloadsRemoved.Add(jsonPayload);
- }
-
- public void PerformRemove(IEnumerable servers, ICacheRefresher refresher, Func getNumericId, params T[] instances)
- {
- IntIdsRemoved.AddRange(instances.Select(getNumericId));
- }
-
- public void PerformRemove(IEnumerable servers, ICacheRefresher refresher, params int[] numericIds)
- {
- IntIdsRemoved.AddRange(numericIds);
- }
-
- public void PerformRefresh(IEnumerable servers, ICacheRefresher refresher, params int[] numericIds)
- {
- IntIdsRefreshed.AddRange(numericIds);
- }
-
- public void PerformRefresh(IEnumerable servers, ICacheRefresher refresher, params Guid[] guidIds)
- {
- GuidIdsRefreshed.AddRange(guidIds);
- }
-
- public void PerformRefreshAll(IEnumerable servers, ICacheRefresher refresher)
- {
- CountOfFullRefreshes++;
- }
- }
-
- internal class TestServerRegistrar : IServerRegistrar
- {
- public IEnumerable Registrations
- {
- get
- {
- return new List()
- {
- new TestServerAddress("localhost")
- };
- }
- }
- }
-
- public class TestServerAddress : IServerAddress
- {
- public TestServerAddress(string address)
- {
- ServerAddress = address;
- }
- public string ServerAddress { get; private set; }
- }
-
- #endregion
- }
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using NUnit.Framework;
+using Umbraco.Core;
+using Umbraco.Core.ObjectResolution;
+using Umbraco.Core.Sync;
+using umbraco.interfaces;
+
+namespace Umbraco.Tests.DistributedCache
+{
+ ///
+ /// Ensures that calls to DistributedCache methods carry through to the IServerMessenger correctly
+ ///
+ [TestFixture]
+ public class DistributedCacheTests
+ {
+ [SetUp]
+ public void Setup()
+ {
+ ServerRegistrarResolver.Current = new ServerRegistrarResolver(
+ new TestServerRegistrar());
+ ServerMessengerResolver.Current = new ServerMessengerResolver(
+ new TestServerMessenger());
+ CacheRefreshersResolver.Current = new CacheRefreshersResolver(() => new[] { typeof(TestCacheRefresher) });
+ Resolution.Freeze();
+ }
+
+ [TearDown]
+ public void Teardown()
+ {
+ ServerRegistrarResolver.Reset();
+ ServerMessengerResolver.Reset();
+ CacheRefreshersResolver.Reset();
+ }
+
+ [Test]
+ public void RefreshIntId()
+ {
+ for (var i = 1; i < 11; i++)
+ {
+ Web.Cache.DistributedCache.Instance.Refresh(Guid.Parse("E0F452CB-DCB2-4E84-B5A5-4F01744C5C73"), i);
+ }
+ Assert.AreEqual(10, ((TestServerMessenger)ServerMessengerResolver.Current.Messenger).IntIdsRefreshed.Count);
+ }
+
+ [Test]
+ public void RefreshIntIdFromObject()
+ {
+ for (var i = 0; i < 10; i++)
+ {
+ Web.Cache.DistributedCache.Instance.Refresh(
+ Guid.Parse("E0F452CB-DCB2-4E84-B5A5-4F01744C5C73"),
+ x => x.Id,
+ new TestObjectWithId{Id = i});
+ }
+ Assert.AreEqual(10, ((TestServerMessenger)ServerMessengerResolver.Current.Messenger).IntIdsRefreshed.Count);
+ }
+
+ [Test]
+ public void RefreshGuidId()
+ {
+ for (var i = 0; i < 11; i++)
+ {
+ Web.Cache.DistributedCache.Instance.Refresh(Guid.Parse("E0F452CB-DCB2-4E84-B5A5-4F01744C5C73"), Guid.NewGuid());
+ }
+ Assert.AreEqual(11, ((TestServerMessenger)ServerMessengerResolver.Current.Messenger).GuidIdsRefreshed.Count);
+ }
+
+ [Test]
+ public void RemoveIds()
+ {
+ for (var i = 1; i < 13; i++)
+ {
+ Web.Cache.DistributedCache.Instance.Remove(Guid.Parse("E0F452CB-DCB2-4E84-B5A5-4F01744C5C73"), i);
+ }
+ Assert.AreEqual(12, ((TestServerMessenger)ServerMessengerResolver.Current.Messenger).IntIdsRemoved.Count);
+ }
+
+ [Test]
+ public void FullRefreshes()
+ {
+ for (var i = 0; i < 13; i++)
+ {
+ Web.Cache.DistributedCache.Instance.RefreshAll(Guid.Parse("E0F452CB-DCB2-4E84-B5A5-4F01744C5C73"));
+ }
+ Assert.AreEqual(13, ((TestServerMessenger)ServerMessengerResolver.Current.Messenger).CountOfFullRefreshes);
+ }
+
+ #region internal test classes
+
+ internal class TestObjectWithId
+ {
+ public int Id { get; set; }
+ }
+
+ internal class TestCacheRefresher : ICacheRefresher
+ {
+ public Guid UniqueIdentifier
+ {
+ get { return Guid.Parse("E0F452CB-DCB2-4E84-B5A5-4F01744C5C73"); }
+ }
+ public string Name
+ {
+ get { return "Test"; }
+ }
+ public void RefreshAll()
+ {
+
+ }
+
+ public void Refresh(int id)
+ {
+
+ }
+
+ public void Remove(int id)
+ {
+
+ }
+
+ public void Refresh(Guid id)
+ {
+
+ }
+ }
+
+ internal class TestServerMessenger : IServerMessenger
+ {
+ //used for tests
+ public List IntIdsRefreshed = new List();
+ public List GuidIdsRefreshed = new List();
+ public List IntIdsRemoved = new List();
+ public List PayloadsRemoved = new List();
+ public List PayloadsRefreshed = new List();
+ public int CountOfFullRefreshes = 0;
+
+
+ public void PerformRefresh(IEnumerable servers, ICacheRefresher refresher, string jsonPayload)
+ {
+ PayloadsRefreshed.Add(jsonPayload);
+ }
+
+ public void PerformRefresh(IEnumerable servers, ICacheRefresher refresher, Func getNumericId, params T[] instances)
+ {
+ IntIdsRefreshed.AddRange(instances.Select(getNumericId));
+ }
+
+ public void PerformRefresh(IEnumerable servers, ICacheRefresher refresher, Func getGuidId, params T[] instances)
+ {
+ GuidIdsRefreshed.AddRange(instances.Select(getGuidId));
+ }
+
+ public void PerformRemove(IEnumerable servers, ICacheRefresher refresher, string jsonPayload)
+ {
+ PayloadsRemoved.Add(jsonPayload);
+ }
+
+ public void PerformRemove(IEnumerable servers, ICacheRefresher refresher, Func getNumericId, params T[] instances)
+ {
+ IntIdsRemoved.AddRange(instances.Select(getNumericId));
+ }
+
+ public void PerformRemove(IEnumerable servers, ICacheRefresher refresher, params int[] numericIds)
+ {
+ IntIdsRemoved.AddRange(numericIds);
+ }
+
+ public void PerformRefresh(IEnumerable servers, ICacheRefresher refresher, params int[] numericIds)
+ {
+ IntIdsRefreshed.AddRange(numericIds);
+ }
+
+ public void PerformRefresh(IEnumerable servers, ICacheRefresher refresher, params Guid[] guidIds)
+ {
+ GuidIdsRefreshed.AddRange(guidIds);
+ }
+
+ public void PerformRefreshAll(IEnumerable servers, ICacheRefresher refresher)
+ {
+ CountOfFullRefreshes++;
+ }
+ }
+
+ internal class TestServerRegistrar : IServerRegistrar
+ {
+ public IEnumerable Registrations
+ {
+ get
+ {
+ return new List()
+ {
+ new TestServerAddress("localhost")
+ };
+ }
+ }
+ }
+
+ public class TestServerAddress : IServerAddress
+ {
+ public TestServerAddress(string address)
+ {
+ ServerAddress = address;
+ }
+ public string ServerAddress { get; private set; }
+ }
+
+ #endregion
+ }
}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/Dynamics/QueryableExtensionTests.cs b/src/Umbraco.Tests/DynamicsAndReflection/QueryableExtensionTests.cs
similarity index 95%
rename from src/Umbraco.Tests/Dynamics/QueryableExtensionTests.cs
rename to src/Umbraco.Tests/DynamicsAndReflection/QueryableExtensionTests.cs
index d5343ff521..c2544421a0 100644
--- a/src/Umbraco.Tests/Dynamics/QueryableExtensionTests.cs
+++ b/src/Umbraco.Tests/DynamicsAndReflection/QueryableExtensionTests.cs
@@ -1,162 +1,158 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using NUnit.Framework;
-using Umbraco.Core.Dynamics;
-using Umbraco.Web.Dynamics;
-using Umbraco.Core.Models;
-
-namespace Umbraco.Tests.Dynamics
-{
- //NOTE: there's libraries in both Umbraco.Core.Dynamics and Umbraco.Web.Dynamics - the reason for this is that the Web.Dynamics
- // started with the razor macro implementation and is modified with hard coded references to dynamic node and dynamic null, though it seems
- // to still work for other regular classes I don't want to move it to the core without removing these references but that would require a lot of work.
-
- [TestFixture]
- public class QueryableExtensionTests
- {
-
- [Test]
- public void Order_By_Test_Int()
- {
- var items = new List
- {
- new TestModel {Age = 10, Name = "test1", Female = false},
- new TestModel {Age = 31, Name = "someguy", Female = true},
- new TestModel {Age = 11, Name = "test2", Female = true},
- new TestModel {Age = 20, Name = "anothertest", Female = false},
- new TestModel {Age = 55, Name = "blah", Female = false},
- new TestModel {Age = 12, Name = "test3", Female = false}
- };
-
- var result = items.AsQueryable().OrderBy("Age").ToArray();
-
- Assert.AreEqual(10, result.ElementAt(0).Age);
- Assert.AreEqual(11, result.ElementAt(1).Age);
- Assert.AreEqual(12, result.ElementAt(2).Age);
- Assert.AreEqual(20, result.ElementAt(3).Age);
- Assert.AreEqual(31, result.ElementAt(4).Age);
- Assert.AreEqual(55, result.ElementAt(5).Age);
-
- }
-
- [Test]
- public void Order_By_Test_String()
- {
- var items = new List
- {
- new TestModel {Age = 10, Name = "test1", Female = false},
- new TestModel {Age = 31, Name = "someguy", Female = true},
- new TestModel {Age = 11, Name = "test2", Female = true},
- new TestModel {Age = 20, Name = "anothertest", Female = false},
- new TestModel {Age = 55, Name = "blah", Female = false},
- new TestModel {Age = 12, Name = "test3", Female = false}
- };
-
- var result = items.AsQueryable().OrderBy("Name").ToArray();
-
- Assert.AreEqual("anothertest", result.ElementAt(0).Name);
- Assert.AreEqual("blah", result.ElementAt(1).Name);
- Assert.AreEqual("someguy", result.ElementAt(2).Name);
- Assert.AreEqual("test1", result.ElementAt(3).Name);
- Assert.AreEqual("test2", result.ElementAt(4).Name);
- Assert.AreEqual("test3", result.ElementAt(5).Name);
-
- }
-
- [Test]
- public void Where_Test_String()
- {
- var items = new List
- {
- new TestModel {Age = 10, Name = "test1", Female = false},
- new TestModel {Age = 31, Name = "someguy", Female = true},
- new TestModel {Age = 11, Name = "test2", Female = true},
- new TestModel {Age = 20, Name = "anothertest", Female = false},
- new TestModel {Age = 55, Name = "blah", Female = false},
- new TestModel {Age = 12, Name = "test3", Female = false}
- };
-
- var result = items.AsQueryable().Where("Name = \"test1\"").ToArray();
-
- Assert.AreEqual(1, result.Count());
- Assert.AreEqual("test1", result.ElementAt(0).Name);
-
-
- }
-
- [Test]
- public void Where_Test_String_With_Params()
- {
- var items = new List
- {
- new TestModel {Age = 10, Name = "test1", Female = false},
- new TestModel {Age = 31, Name = "someguy", Female = true},
- new TestModel {Age = 11, Name = "test2", Female = true},
- new TestModel {Age = 20, Name = "anothertest", Female = false},
- new TestModel {Age = 55, Name = "blah", Female = false},
- new TestModel {Age = 12, Name = "test3", Female = false}
- };
-
- //NOTE: Currently the object query structure is not supported
- //var result = items.AsQueryable().Where("Name = @name", new {name = "test1"}).ToArray();
- var result = items.AsQueryable().Where("Name = @Name", new Dictionary { { "Name", "test1" } }).ToArray();
-
- Assert.AreEqual(1, result.Count());
- Assert.AreEqual("test1", result.ElementAt(0).Name);
-
-
- }
-
- [Test]
- public void Where_Test_Int_With_Params()
- {
- var items = new List
- {
- new TestModel {Age = 10, Name = "test1", Female = false},
- new TestModel {Age = 31, Name = "someguy", Female = true},
- new TestModel {Age = 11, Name = "test2", Female = true},
- new TestModel {Age = 20, Name = "anothertest", Female = false},
- new TestModel {Age = 55, Name = "blah", Female = false},
- new TestModel {Age = 12, Name = "test3", Female = false}
- };
-
- var result = items.AsQueryable().Where("Age = @Age", new Dictionary { { "Age", 10 } }).ToArray();
-
- Assert.AreEqual(1, result.Count());
- Assert.AreEqual("test1", result.ElementAt(0).Name);
-
-
- }
-
- [Test]
- public void Where_Test_Bool_With_Params()
- {
- var items = new List
- {
- new TestModel {Age = 10, Name = "test1", Female = false},
- new TestModel {Age = 31, Name = "someguy", Female = true},
- new TestModel {Age = 11, Name = "test2", Female = true},
- new TestModel {Age = 20, Name = "anothertest", Female = false},
- new TestModel {Age = 55, Name = "blah", Female = false},
- new TestModel {Age = 12, Name = "test3", Female = false}
- };
-
- var result = items.AsQueryable().Where("Female = @Female", new Dictionary { { "Female", true } }).ToArray();
-
- Assert.AreEqual(2, result.Count());
-
-
- }
-
- private class TestModel
- {
- public string Name { get; set; }
- public int Age { get; set; }
- public bool Female { get; set; }
- }
-
- }
-}
+using System.Collections.Generic;
+using System.Linq;
+using NUnit.Framework;
+using Umbraco.Core.Dynamics;
+using Umbraco.Web.Dynamics;
+
+namespace Umbraco.Tests.DynamicsAndReflection
+{
+ //NOTE: there's libraries in both Umbraco.Core.Dynamics and Umbraco.Web.Dynamics - the reason for this is that the Web.Dynamics
+ // started with the razor macro implementation and is modified with hard coded references to dynamic node and dynamic null, though it seems
+ // to still work for other regular classes I don't want to move it to the core without removing these references but that would require a lot of work.
+
+ [TestFixture]
+ public class QueryableExtensionTests
+ {
+
+ [Test]
+ public void Order_By_Test_Int()
+ {
+ var items = new List
+ {
+ new TestModel {Age = 10, Name = "test1", Female = false},
+ new TestModel {Age = 31, Name = "someguy", Female = true},
+ new TestModel {Age = 11, Name = "test2", Female = true},
+ new TestModel {Age = 20, Name = "anothertest", Female = false},
+ new TestModel {Age = 55, Name = "blah", Female = false},
+ new TestModel {Age = 12, Name = "test3", Female = false}
+ };
+
+ var result = items.AsQueryable().OrderBy("Age").ToArray();
+
+ Assert.AreEqual(10, result.ElementAt(0).Age);
+ Assert.AreEqual(11, result.ElementAt(1).Age);
+ Assert.AreEqual(12, result.ElementAt(2).Age);
+ Assert.AreEqual(20, result.ElementAt(3).Age);
+ Assert.AreEqual(31, result.ElementAt(4).Age);
+ Assert.AreEqual(55, result.ElementAt(5).Age);
+
+ }
+
+ [Test]
+ public void Order_By_Test_String()
+ {
+ var items = new List
+ {
+ new TestModel {Age = 10, Name = "test1", Female = false},
+ new TestModel {Age = 31, Name = "someguy", Female = true},
+ new TestModel {Age = 11, Name = "test2", Female = true},
+ new TestModel {Age = 20, Name = "anothertest", Female = false},
+ new TestModel {Age = 55, Name = "blah", Female = false},
+ new TestModel {Age = 12, Name = "test3", Female = false}
+ };
+
+ var result = items.AsQueryable().OrderBy("Name").ToArray();
+
+ Assert.AreEqual("anothertest", result.ElementAt(0).Name);
+ Assert.AreEqual("blah", result.ElementAt(1).Name);
+ Assert.AreEqual("someguy", result.ElementAt(2).Name);
+ Assert.AreEqual("test1", result.ElementAt(3).Name);
+ Assert.AreEqual("test2", result.ElementAt(4).Name);
+ Assert.AreEqual("test3", result.ElementAt(5).Name);
+
+ }
+
+ [Test]
+ public void Where_Test_String()
+ {
+ var items = new List
+ {
+ new TestModel {Age = 10, Name = "test1", Female = false},
+ new TestModel {Age = 31, Name = "someguy", Female = true},
+ new TestModel {Age = 11, Name = "test2", Female = true},
+ new TestModel {Age = 20, Name = "anothertest", Female = false},
+ new TestModel {Age = 55, Name = "blah", Female = false},
+ new TestModel {Age = 12, Name = "test3", Female = false}
+ };
+
+ var result = items.AsQueryable().Where("Name = \"test1\"").ToArray();
+
+ Assert.AreEqual(1, result.Count());
+ Assert.AreEqual("test1", result.ElementAt(0).Name);
+
+
+ }
+
+ [Test]
+ public void Where_Test_String_With_Params()
+ {
+ var items = new List
+ {
+ new TestModel {Age = 10, Name = "test1", Female = false},
+ new TestModel {Age = 31, Name = "someguy", Female = true},
+ new TestModel {Age = 11, Name = "test2", Female = true},
+ new TestModel {Age = 20, Name = "anothertest", Female = false},
+ new TestModel {Age = 55, Name = "blah", Female = false},
+ new TestModel {Age = 12, Name = "test3", Female = false}
+ };
+
+ //NOTE: Currently the object query structure is not supported
+ //var result = items.AsQueryable().Where("Name = @name", new {name = "test1"}).ToArray();
+ var result = items.AsQueryable().Where("Name = @Name", new Dictionary { { "Name", "test1" } }).ToArray();
+
+ Assert.AreEqual(1, result.Count());
+ Assert.AreEqual("test1", result.ElementAt(0).Name);
+
+
+ }
+
+ [Test]
+ public void Where_Test_Int_With_Params()
+ {
+ var items = new List
+ {
+ new TestModel {Age = 10, Name = "test1", Female = false},
+ new TestModel {Age = 31, Name = "someguy", Female = true},
+ new TestModel {Age = 11, Name = "test2", Female = true},
+ new TestModel {Age = 20, Name = "anothertest", Female = false},
+ new TestModel {Age = 55, Name = "blah", Female = false},
+ new TestModel {Age = 12, Name = "test3", Female = false}
+ };
+
+ var result = items.AsQueryable().Where("Age = @Age", new Dictionary { { "Age", 10 } }).ToArray();
+
+ Assert.AreEqual(1, result.Count());
+ Assert.AreEqual("test1", result.ElementAt(0).Name);
+
+
+ }
+
+ [Test]
+ public void Where_Test_Bool_With_Params()
+ {
+ var items = new List
+ {
+ new TestModel {Age = 10, Name = "test1", Female = false},
+ new TestModel {Age = 31, Name = "someguy", Female = true},
+ new TestModel {Age = 11, Name = "test2", Female = true},
+ new TestModel {Age = 20, Name = "anothertest", Female = false},
+ new TestModel {Age = 55, Name = "blah", Female = false},
+ new TestModel {Age = 12, Name = "test3", Female = false}
+ };
+
+ var result = items.AsQueryable().Where("Female = @Female", new Dictionary { { "Female", true } }).ToArray();
+
+ Assert.AreEqual(2, result.Count());
+
+
+ }
+
+ private class TestModel
+ {
+ public string Name { get; set; }
+ public int Age { get; set; }
+ public bool Female { get; set; }
+ }
+
+ }
+}
diff --git a/src/Umbraco.Tests/MacroEngineFactoryTests.cs b/src/Umbraco.Tests/Macros/MacroEngineFactoryTests.cs
similarity index 95%
rename from src/Umbraco.Tests/MacroEngineFactoryTests.cs
rename to src/Umbraco.Tests/Macros/MacroEngineFactoryTests.cs
index e8d35e8255..2ab4c9f04e 100644
--- a/src/Umbraco.Tests/MacroEngineFactoryTests.cs
+++ b/src/Umbraco.Tests/Macros/MacroEngineFactoryTests.cs
@@ -1,139 +1,139 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using NUnit.Framework;
-using Umbraco.Core;
-using Umbraco.Tests.TestHelpers;
-using umbraco.cms.businesslogic.macro;
-using umbraco.interfaces;
-
-namespace Umbraco.Tests
-{
- [TestFixture]
- public class MacroEngineFactoryTests
- {
- [SetUp]
- public void Initialize()
- {
- TestHelper.SetupLog4NetForTests();
-
- //this ensures its reset
- PluginManager.Current = new PluginManager(false);
-
- //for testing, we'll specify which assemblies are scanned for the PluginTypeResolver
- PluginManager.Current.AssembliesToScan = new[]
- {
- this.GetType().Assembly
- };
- }
-
- [TearDown]
- public void TearDown()
- {
- PluginManager.Current = null;
- }
-
- [Test]
- public void Get_All()
- {
- var engines = MacroEngineFactory.GetAll();
- Assert.AreEqual(2, engines.Count());
- }
-
- [Test]
- public void Get_Engine()
- {
- var engine1 = MacroEngineFactory.GetEngine("MacroEngine1");
- Assert.IsNotNull(engine1);
- }
-
- [Test]
- public void Get_By_Filename()
- {
- var engine1 = MacroEngineFactory.GetByFilename("test.me1");
- var engine2 = MacroEngineFactory.GetByFilename("test.me2");
- Assert.IsNotNull(engine1);
- Assert.IsNotNull(engine2);
- Assert.Throws(() => MacroEngineFactory.GetByFilename("test.blah"));
-
- }
-
- [Test]
- public void Get_By_Extension()
- {
- var engine1 = MacroEngineFactory.GetByExtension("me1");
- var engine2 = MacroEngineFactory.GetByExtension("me2");
- Assert.IsNotNull(engine1);
- Assert.IsNotNull(engine2);
- Assert.Throws(() => MacroEngineFactory.GetByExtension("blah"));
- }
-
- #region Classes for tests
- public class MacroEngine1 : IMacroEngine
- {
- public string Name
- {
- get { return "MacroEngine1"; }
- }
-
- public IEnumerable SupportedExtensions
- {
- get { return new[] {"me1"}; }
- }
-
- public IEnumerable SupportedUIExtensions
- {
- get { throw new NotImplementedException(); }
- }
-
- public Dictionary SupportedProperties
- {
- get { throw new NotImplementedException(); }
- }
-
- public bool Validate(string code, string tempFileName, INode currentPage, out string errorMessage)
- {
- throw new NotImplementedException();
- }
-
- public string Execute(MacroModel macro, INode currentPage)
- {
- throw new NotImplementedException();
- }
- }
-
- public class MacroEngine2 : IMacroEngine
- {
- public string Name
- {
- get { return "MacroEngine2"; }
- }
-
- public IEnumerable SupportedExtensions
- {
- get { return new[] { "me2" }; }
- }
-
- public IEnumerable SupportedUIExtensions
- {
- get { throw new NotImplementedException(); }
- }
-
- public Dictionary SupportedProperties
- {
- get { throw new NotImplementedException(); }
- }
-
- public bool Validate(string code, string tempFileName, INode currentPage, out string errorMessage)
- {
- throw new NotImplementedException();
- }
-
- public string Execute(MacroModel macro, INode currentPage)
- {
- throw new NotImplementedException();
- }
- }
- #endregion
- }
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using NUnit.Framework;
+using umbraco.cms.businesslogic.macro;
+using Umbraco.Core;
+using umbraco.interfaces;
+using Umbraco.Tests.TestHelpers;
+
+namespace Umbraco.Tests.Macros
+{
+ [TestFixture]
+ public class MacroEngineFactoryTests
+ {
+ [SetUp]
+ public void Initialize()
+ {
+ TestHelper.SetupLog4NetForTests();
+
+ //this ensures its reset
+ PluginManager.Current = new PluginManager(false);
+
+ //for testing, we'll specify which assemblies are scanned for the PluginTypeResolver
+ PluginManager.Current.AssembliesToScan = new[]
+ {
+ this.GetType().Assembly
+ };
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ PluginManager.Current = null;
+ }
+
+ [Test]
+ public void Get_All()
+ {
+ var engines = MacroEngineFactory.GetAll();
+ Assert.AreEqual(2, engines.Count());
+ }
+
+ [Test]
+ public void Get_Engine()
+ {
+ var engine1 = MacroEngineFactory.GetEngine("MacroEngine1");
+ Assert.IsNotNull(engine1);
+ }
+
+ [Test]
+ public void Get_By_Filename()
+ {
+ var engine1 = MacroEngineFactory.GetByFilename("test.me1");
+ var engine2 = MacroEngineFactory.GetByFilename("test.me2");
+ Assert.IsNotNull(engine1);
+ Assert.IsNotNull(engine2);
+ Assert.Throws(() => MacroEngineFactory.GetByFilename("test.blah"));
+
+ }
+
+ [Test]
+ public void Get_By_Extension()
+ {
+ var engine1 = MacroEngineFactory.GetByExtension("me1");
+ var engine2 = MacroEngineFactory.GetByExtension("me2");
+ Assert.IsNotNull(engine1);
+ Assert.IsNotNull(engine2);
+ Assert.Throws(() => MacroEngineFactory.GetByExtension("blah"));
+ }
+
+ #region Classes for tests
+ public class MacroEngine1 : IMacroEngine
+ {
+ public string Name
+ {
+ get { return "MacroEngine1"; }
+ }
+
+ public IEnumerable SupportedExtensions
+ {
+ get { return new[] {"me1"}; }
+ }
+
+ public IEnumerable SupportedUIExtensions
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public Dictionary SupportedProperties
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public bool Validate(string code, string tempFileName, INode currentPage, out string errorMessage)
+ {
+ throw new NotImplementedException();
+ }
+
+ public string Execute(MacroModel macro, INode currentPage)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public class MacroEngine2 : IMacroEngine
+ {
+ public string Name
+ {
+ get { return "MacroEngine2"; }
+ }
+
+ public IEnumerable SupportedExtensions
+ {
+ get { return new[] { "me2" }; }
+ }
+
+ public IEnumerable SupportedUIExtensions
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public Dictionary SupportedProperties
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public bool Validate(string code, string tempFileName, INode currentPage, out string errorMessage)
+ {
+ throw new NotImplementedException();
+ }
+
+ public string Execute(MacroModel macro, INode currentPage)
+ {
+ throw new NotImplementedException();
+ }
+ }
+ #endregion
+ }
}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/HtmlHelperExtensionMethodsTests.cs b/src/Umbraco.Tests/Mvc/HtmlHelperExtensionMethodsTests.cs
similarity index 93%
rename from src/Umbraco.Tests/HtmlHelperExtensionMethodsTests.cs
rename to src/Umbraco.Tests/Mvc/HtmlHelperExtensionMethodsTests.cs
index 5efabd891e..beb51fa651 100644
--- a/src/Umbraco.Tests/HtmlHelperExtensionMethodsTests.cs
+++ b/src/Umbraco.Tests/Mvc/HtmlHelperExtensionMethodsTests.cs
@@ -1,33 +1,33 @@
-using System.Web.Mvc;
-using NUnit.Framework;
-using Umbraco.Web;
-
-namespace Umbraco.Tests
-{
- [TestFixture]
- public class HtmlHelperExtensionMethodsTests
- {
- [SetUp]
- public virtual void Initialize()
- {
- //create an empty htmlHelper
- _htmlHelper = new HtmlHelper(new ViewContext(), new ViewPage());
- }
-
- private HtmlHelper _htmlHelper;
-
- [Test]
- public void Wrap_Simple()
- {
- var output = _htmlHelper.Wrap("div", "hello world");
- Assert.AreEqual("hello world
", output.ToHtmlString());
- }
-
- [Test]
- public void Wrap_Object_Attributes()
- {
- var output = _htmlHelper.Wrap("div", "hello world", new {style = "color:red;", onclick = "void();"});
- Assert.AreEqual("hello world
", output.ToHtmlString());
- }
- }
+using System.Web.Mvc;
+using NUnit.Framework;
+using Umbraco.Web;
+
+namespace Umbraco.Tests.Mvc
+{
+ [TestFixture]
+ public class HtmlHelperExtensionMethodsTests
+ {
+ [SetUp]
+ public virtual void Initialize()
+ {
+ //create an empty htmlHelper
+ _htmlHelper = new HtmlHelper(new ViewContext(), new ViewPage());
+ }
+
+ private HtmlHelper _htmlHelper;
+
+ [Test]
+ public void Wrap_Simple()
+ {
+ var output = _htmlHelper.Wrap("div", "hello world");
+ Assert.AreEqual("hello world
", output.ToHtmlString());
+ }
+
+ [Test]
+ public void Wrap_Object_Attributes()
+ {
+ var output = _htmlHelper.Wrap("div", "hello world", new {style = "color:red;", onclick = "void();"});
+ Assert.AreEqual("hello world
", output.ToHtmlString());
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/PluginManagerExtensions.cs b/src/Umbraco.Tests/Plugins/PluginManagerExtensions.cs
similarity index 89%
rename from src/Umbraco.Tests/PluginManagerExtensions.cs
rename to src/Umbraco.Tests/Plugins/PluginManagerExtensions.cs
index 0daad7be44..b8ff7d20c2 100644
--- a/src/Umbraco.Tests/PluginManagerExtensions.cs
+++ b/src/Umbraco.Tests/Plugins/PluginManagerExtensions.cs
@@ -1,17 +1,17 @@
-using System;
-using System.Collections.Generic;
-using Umbraco.Core;
-
-namespace Umbraco.Tests
-{
- ///
- /// Used for PluginTypeResolverTests
- ///
- internal static class PluginManagerExtensions
- {
- public static IEnumerable ResolveFindMeTypes(this PluginManager resolver)
- {
- return resolver.ResolveTypes();
- }
- }
+using System;
+using System.Collections.Generic;
+using Umbraco.Core;
+
+namespace Umbraco.Tests.Plugins
+{
+ ///
+ /// Used for PluginTypeResolverTests
+ ///
+ internal static class PluginManagerExtensions
+ {
+ public static IEnumerable ResolveFindMeTypes(this PluginManager resolver)
+ {
+ return resolver.ResolveTypes();
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/PluginManagerTests.cs b/src/Umbraco.Tests/Plugins/PluginManagerTests.cs
similarity index 96%
rename from src/Umbraco.Tests/PluginManagerTests.cs
rename to src/Umbraco.Tests/Plugins/PluginManagerTests.cs
index 8c510256f3..aa9fc7339f 100644
--- a/src/Umbraco.Tests/PluginManagerTests.cs
+++ b/src/Umbraco.Tests/Plugins/PluginManagerTests.cs
@@ -1,30 +1,26 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
-using System.Web.Compilation;
using NUnit.Framework;
using SqlCE4Umbraco;
+using umbraco;
+using umbraco.businesslogic;
+using umbraco.cms.businesslogic;
using Umbraco.Core;
using Umbraco.Core.IO;
using Umbraco.Core.PropertyEditors;
+using umbraco.DataLayer;
+using umbraco.editorControls;
+using umbraco.MacroEngines;
using Umbraco.Tests.TestHelpers;
+using umbraco.uicontrols;
using Umbraco.Web;
using Umbraco.Web.PropertyEditors;
-using umbraco;
-using umbraco.DataLayer;
-using umbraco.MacroEngines;
-using umbraco.businesslogic;
-using umbraco.cms.businesslogic;
-using umbraco.editorControls;
-using umbraco.interfaces;
-using umbraco.uicontrols;
-using umbraco.cms;
-namespace Umbraco.Tests
+namespace Umbraco.Tests.Plugins
{
[TestFixture]
diff --git a/src/Umbraco.Tests/TypeFinderTests.cs b/src/Umbraco.Tests/Plugins/TypeFinderTests.cs
similarity index 97%
rename from src/Umbraco.Tests/TypeFinderTests.cs
rename to src/Umbraco.Tests/Plugins/TypeFinderTests.cs
index d9952a9ac0..8611570ef3 100644
--- a/src/Umbraco.Tests/TypeFinderTests.cs
+++ b/src/Umbraco.Tests/Plugins/TypeFinderTests.cs
@@ -1,641 +1,638 @@
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Security;
-using System.Text;
-using System.Threading;
-using System.Web;
-using System.Web.Compilation;
-using NUnit.Framework;
-using SqlCE4Umbraco;
-using Umbraco.Core;
-using Umbraco.Core.IO;
-using Umbraco.Core.Logging;
-using Umbraco.Tests;
-using Umbraco.Tests.TestHelpers;
-using Umbraco.Web.BaseRest;
-using umbraco;
-using umbraco.DataLayer;
-using umbraco.MacroEngines;
-using umbraco.businesslogic;
-using umbraco.cms.businesslogic;
-using umbraco.editorControls.tags;
-using umbraco.interfaces;
-using umbraco.uicontrols;
-
-namespace Umbraco.Tests
-{
-
- ///
- /// Tests for typefinder
- ///
- [TestFixture]
- public class TypeFinderTests
- {
- ///
- /// List of assemblies to scan
- ///
- private Assembly[] _assemblies;
-
- [SetUp]
- public void Initialize()
- {
- TestHelper.SetupLog4NetForTests();
-
- _assemblies = new[]
- {
- this.GetType().Assembly,
- typeof(ApplicationStartupHandler).Assembly,
- typeof(SqlCEHelper).Assembly,
- typeof(CMSNode).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(ISqlHelper).Assembly,
- typeof(ICultureDictionary).Assembly,
- typeof(Tag).Assembly,
- typeof(global::UmbracoExamine.BaseUmbracoIndexer).Assembly
- };
-
- }
-
- [Test]
- public void Find_Class_Of_Type_With_Attribute()
- {
-
- var typesFound = TypeFinder.FindClassesOfTypeWithAttribute(_assemblies);
- Assert.AreEqual(2, typesFound.Count());
- }
-
- [Test]
- public void Find_Classes_Of_Type()
- {
- var typesFound = TypeFinder.FindClassesOfType(_assemblies);
- var originalTypesFound = TypeFinderOriginal.FindClassesOfType(_assemblies);
-
- Assert.AreEqual(originalTypesFound.Count(), typesFound.Count());
- Assert.AreEqual(5, typesFound.Count());
- Assert.AreEqual(5, originalTypesFound.Count());
- }
-
- [Test]
- public void Find_Classes_With_Attribute()
- {
- var typesFound = TypeFinder.FindClassesWithAttribute(_assemblies);
- Assert.AreEqual(1, typesFound.Count());
- }
-
- [Ignore]
- [Test]
- public void Benchmark_Original_Finder()
- {
- using (DisposableTimer.TraceDuration("Starting test", "Finished test"))
- {
- using (DisposableTimer.TraceDuration("Starting FindClassesOfType", "Finished FindClassesOfType"))
- {
- for (var i = 0; i < 1000; i++)
- {
- Assert.Greater(TypeFinderOriginal.FindClassesOfType(_assemblies).Count(), 0);
- }
- }
- using (DisposableTimer.TraceDuration("Starting FindClassesOfTypeWithAttribute", "Finished FindClassesOfTypeWithAttribute"))
- {
- for (var i = 0; i < 1000; i++)
- {
- Assert.Greater(TypeFinderOriginal.FindClassesOfTypeWithAttribute(_assemblies).Count(), 0);
- }
- }
- using (DisposableTimer.TraceDuration("Starting FindClassesWithAttribute", "Finished FindClassesWithAttribute"))
- {
- for (var i = 0; i < 1000; i++)
- {
- Assert.Greater(TypeFinderOriginal.FindClassesWithAttribute(_assemblies).Count(), 0);
- }
- }
- }
-
- }
-
- [Ignore]
- [Test]
- public void Benchmark_New_Finder()
- {
- using (DisposableTimer.TraceDuration("Starting test", "Finished test"))
- {
- using (DisposableTimer.TraceDuration("Starting FindClassesOfType", "Finished FindClassesOfType"))
- {
- for (var i = 0; i < 1000; i++)
- {
- Assert.Greater(TypeFinder.FindClassesOfType(_assemblies).Count(), 0);
- }
- }
- using (DisposableTimer.TraceDuration("Starting FindClassesOfTypeWithAttribute", "Finished FindClassesOfTypeWithAttribute"))
- {
- for (var i = 0; i < 1000; i++)
- {
- Assert.Greater(TypeFinder.FindClassesOfTypeWithAttribute(_assemblies).Count(), 0);
- }
- }
- using (DisposableTimer.TraceDuration("Starting FindClassesWithAttribute", "Finished FindClassesWithAttribute"))
- {
- for (var i = 0; i < 1000; i++)
- {
- Assert.Greater(TypeFinder.FindClassesWithAttribute(_assemblies).Count(), 0);
- }
- }
- }
-
- }
-
- public class MyTag : ITag
- {
- public int Id { get; private set; }
- public string TagCaption { get; private set; }
- public string Group { get; private set; }
- }
-
- public class MySuperTag : MyTag
- {
-
- }
-
- [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
- public class MyTestAttribute : Attribute
- {
-
- }
-
- public abstract class TestEditor
- {
-
- }
-
- [MyTestAttribute]
- public class BenchmarkTestEditor : TestEditor
- {
-
- }
-
- [MyTestAttribute]
- public class MyOtherTestEditor : TestEditor
- {
-
- }
-
- //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 LocalFilteredAssemblyCache = new ConcurrentBag();
- private static readonly ReaderWriterLockSlim LocalFilteredAssemblyCacheLocker = new ReaderWriterLockSlim();
- private static ReadOnlyCollection _allAssemblies = null;
- private static ReadOnlyCollection _binFolderAssemblies = null;
- private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
-
- ///
- /// 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
- ///
- ///
- /// 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
- ///
- internal static IEnumerable GetAllAssemblies()
- {
- if (_allAssemblies == null)
- {
- using (new WriteLock(Locker))
- {
- List assemblies = null;
- try
- {
- var isHosted = HttpContext.Current != null;
-
- try
- {
- if (isHosted)
- {
- assemblies = new List(BuildManager.GetReferencedAssemblies().Cast());
- }
- }
- 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();
- 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(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())))
- {
- 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(assemblies);
-
- }
- catch (InvalidOperationException e)
- {
- if (!(e.InnerException is SecurityException))
- throw;
-
- _binFolderAssemblies = _allAssemblies;
- }
- }
- }
-
- return _allAssemblies;
- }
-
- ///
- /// Returns only assemblies found in the bin folder that have been loaded into the app domain.
- ///
- ///
- ///
- /// This will be used if we implement App_Plugins from Umbraco v5 but currently it is not used.
- ///
- internal static IEnumerable 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();
- var binFolderAssemblies = new List();
-
- 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(binFolderAssemblies);
- }
- }
- return _binFolderAssemblies;
- }
-
- ///
- /// 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.
- ///
- ///
- ///
- internal static IEnumerable GetAssembliesWithKnownExclusions(
- IEnumerable excludeFromResults = null)
- {
- if (LocalFilteredAssemblyCache.Any()) return LocalFilteredAssemblyCache;
- using (new WriteLock(LocalFilteredAssemblyCacheLocker))
- {
- var assemblies = GetFilteredAssemblies(excludeFromResults, KnownAssemblyExclusionFilter);
- assemblies.ForEach(LocalFilteredAssemblyCache.Add);
- }
- return LocalFilteredAssemblyCache;
- }
-
- ///
- /// Return a list of found local Assemblies and exluding the ones passed in and excluding the exclusion list filter
- ///
- ///
- ///
- ///
- private static IEnumerable GetFilteredAssemblies(
- IEnumerable excludeFromResults = null,
- string[] exclusionFilter = null)
- {
- if (excludeFromResults == null)
- excludeFromResults = new List();
- if (exclusionFilter == null)
- exclusionFilter = new string[] { };
-
- return GetAllAssemblies()
- .Where(x => !excludeFromResults.Contains(x)
- && !x.GlobalAssemblyCache
- && !exclusionFilter.Any(f => x.FullName.StartsWith(f)));
- }
-
- ///
- /// this is our assembly filter to filter out known types that def dont contain types we'd like to find or plugins
- ///
- ///
- /// 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
- ///
- internal static readonly string[] KnownAssemblyExclusionFilter = new[]
- {
- "mscorlib,",
- "System.",
- "Antlr3.",
- "Autofac.",
- "Autofac,",
- "Castle.",
- "ClientDependency.",
- "DataAnnotationsExtensions.",
- "DataAnnotationsExtensions,",
- "Dynamic,",
- "HtmlDiff,",
- "Iesi.Collections,",
- "log4net,",
- "Microsoft.",
- "Newtonsoft.",
- "NHibernate.",
- "NHibernate,",
- "NuGet.",
- "RouteDebugger,",
- "SqlCE4Umbraco,",
- "umbraco.datalayer,",
- "umbraco.interfaces,",
- "umbraco.providers,",
- "Umbraco.Web.UI,",
- "umbraco.webservices",
- "Lucene.",
- "Examine,",
- "Examine.",
- "ServiceStack.",
- "MySql.",
- "HtmlAgilityPack.",
- "TidyNet.",
- "ICSharpCode.",
- "CookComputing.",
- /* Mono */
- "MonoDevelop.NUnit"
- };
-
- public static IEnumerable FindClassesOfTypeWithAttribute()
- where TAttribute : Attribute
- {
- return FindClassesOfTypeWithAttribute(GetAssembliesWithKnownExclusions(), true);
- }
-
- public static IEnumerable FindClassesOfTypeWithAttribute(IEnumerable assemblies)
- where TAttribute : Attribute
- {
- return FindClassesOfTypeWithAttribute(assemblies, true);
- }
-
- public static IEnumerable FindClassesOfTypeWithAttribute(IEnumerable assemblies, bool onlyConcreteClasses)
- where TAttribute : Attribute
- {
- if (assemblies == null) throw new ArgumentNullException("assemblies");
-
- var l = new List();
- foreach (var a in assemblies)
- {
- var types = from t in GetTypesWithFormattedException(a)
- where !t.IsInterface
- && typeof(T).IsAssignableFrom(t)
- && t.GetCustomAttributes(false).Any()
- && (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract))
- select t;
- l.AddRange(types);
- }
-
- return l;
- }
-
- ///
- /// Searches all filtered local assemblies specified for classes of the type passed in.
- ///
- ///
- ///
- public static IEnumerable FindClassesOfType()
- {
- return FindClassesOfType(GetAssembliesWithKnownExclusions(), true);
- }
-
- ///
- /// Returns all types found of in the assemblies specified of type T
- ///
- ///
- ///
- ///
- ///
- public static IEnumerable FindClassesOfType(IEnumerable assemblies, bool onlyConcreteClasses)
- {
- if (assemblies == null) throw new ArgumentNullException("assemblies");
-
- return GetAssignablesFromType(assemblies, onlyConcreteClasses);
- }
-
- ///
- /// Returns all types found of in the assemblies specified of type T
- ///
- ///
- ///
- ///
- public static IEnumerable FindClassesOfType(IEnumerable assemblies)
- {
- return FindClassesOfType(assemblies, true);
- }
-
- ///
- /// Finds the classes with attribute.
- ///
- ///
- /// The assemblies.
- /// if set to true only concrete classes.
- ///
- public static IEnumerable FindClassesWithAttribute(IEnumerable assemblies, bool onlyConcreteClasses)
- where T : Attribute
- {
- return FindClassesWithAttribute(typeof(T), assemblies, onlyConcreteClasses);
- }
-
- ///
- /// Finds the classes with attribute.
- ///
- /// The attribute type
- /// The assemblies.
- /// if set to true only concrete classes.
- ///
- public static IEnumerable FindClassesWithAttribute(Type type, IEnumerable assemblies, bool onlyConcreteClasses)
- {
- if (assemblies == null) throw new ArgumentNullException("assemblies");
- if (!TypeHelper.IsTypeAssignableFrom(type))
- throw new ArgumentException("The type specified: " + type + " is not an Attribute type");
-
- var l = new List();
- 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;
- }
-
- ///
- /// Finds the classes with attribute.
- ///
- ///
- /// The assemblies.
- ///
- public static IEnumerable FindClassesWithAttribute(IEnumerable assemblies)
- where T : Attribute
- {
- return FindClassesWithAttribute(assemblies, true);
- }
-
- ///
- /// Finds the classes with attribute in filtered local assemblies
- ///
- ///
- ///
- public static IEnumerable FindClassesWithAttribute()
- where T : Attribute
- {
- return FindClassesWithAttribute(GetAssembliesWithKnownExclusions());
- }
-
-
- #region Private methods
-
- ///
- /// Gets a collection of assignables of type T from a collection of assemblies
- ///
- ///
- ///
- ///
- ///
- private static IEnumerable GetAssignablesFromType(IEnumerable assemblies, bool onlyConcreteClasses)
- {
- return GetTypes(typeof(T), assemblies, onlyConcreteClasses);
- }
-
- private static IEnumerable GetTypes(Type assignTypeFrom, IEnumerable assemblies, bool onlyConcreteClasses)
- {
- var l = new List();
- 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 GetTypesWithFormattedException(Assembly a)
- {
- //if the assembly is dynamic, do not try to scan it
- if (a.IsDynamic)
- return Enumerable.Empty();
-
- 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
-
-
-
- }
- }
-
-
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Security;
+using System.Text;
+using System.Threading;
+using System.Web;
+using System.Web.Compilation;
+using NUnit.Framework;
+using SqlCE4Umbraco;
+using umbraco;
+using umbraco.businesslogic;
+using umbraco.cms.businesslogic;
+using Umbraco.Core;
+using Umbraco.Core.IO;
+using umbraco.DataLayer;
+using umbraco.editorControls.tags;
+using umbraco.interfaces;
+using umbraco.MacroEngines;
+using Umbraco.Tests.TestHelpers;
+using umbraco.uicontrols;
+using Umbraco.Web.BaseRest;
+
+namespace Umbraco.Tests.Plugins
+{
+
+ ///
+ /// Tests for typefinder
+ ///
+ [TestFixture]
+ public class TypeFinderTests
+ {
+ ///
+ /// List of assemblies to scan
+ ///
+ private Assembly[] _assemblies;
+
+ [SetUp]
+ public void Initialize()
+ {
+ TestHelper.SetupLog4NetForTests();
+
+ _assemblies = new[]
+ {
+ this.GetType().Assembly,
+ typeof(ApplicationStartupHandler).Assembly,
+ typeof(SqlCEHelper).Assembly,
+ typeof(CMSNode).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(ISqlHelper).Assembly,
+ typeof(ICultureDictionary).Assembly,
+ typeof(Tag).Assembly,
+ typeof(global::UmbracoExamine.BaseUmbracoIndexer).Assembly
+ };
+
+ }
+
+ [Test]
+ public void Find_Class_Of_Type_With_Attribute()
+ {
+
+ var typesFound = TypeFinder.FindClassesOfTypeWithAttribute(_assemblies);
+ Assert.AreEqual(2, typesFound.Count());
+ }
+
+ [Test]
+ public void Find_Classes_Of_Type()
+ {
+ var typesFound = TypeFinder.FindClassesOfType(_assemblies);
+ var originalTypesFound = TypeFinderOriginal.FindClassesOfType(_assemblies);
+
+ Assert.AreEqual(originalTypesFound.Count(), typesFound.Count());
+ Assert.AreEqual(5, typesFound.Count());
+ Assert.AreEqual(5, originalTypesFound.Count());
+ }
+
+ [Test]
+ public void Find_Classes_With_Attribute()
+ {
+ var typesFound = TypeFinder.FindClassesWithAttribute(_assemblies);
+ Assert.AreEqual(1, typesFound.Count());
+ }
+
+ [Ignore]
+ [Test]
+ public void Benchmark_Original_Finder()
+ {
+ using (DisposableTimer.TraceDuration("Starting test", "Finished test"))
+ {
+ using (DisposableTimer.TraceDuration("Starting FindClassesOfType", "Finished FindClassesOfType"))
+ {
+ for (var i = 0; i < 1000; i++)
+ {
+ Assert.Greater(TypeFinderOriginal.FindClassesOfType(_assemblies).Count(), 0);
+ }
+ }
+ using (DisposableTimer.TraceDuration("Starting FindClassesOfTypeWithAttribute", "Finished FindClassesOfTypeWithAttribute"))
+ {
+ for (var i = 0; i < 1000; i++)
+ {
+ Assert.Greater(TypeFinderOriginal.FindClassesOfTypeWithAttribute(_assemblies).Count(), 0);
+ }
+ }
+ using (DisposableTimer.TraceDuration("Starting FindClassesWithAttribute", "Finished FindClassesWithAttribute"))
+ {
+ for (var i = 0; i < 1000; i++)
+ {
+ Assert.Greater(TypeFinderOriginal.FindClassesWithAttribute(_assemblies).Count(), 0);
+ }
+ }
+ }
+
+ }
+
+ [Ignore]
+ [Test]
+ public void Benchmark_New_Finder()
+ {
+ using (DisposableTimer.TraceDuration("Starting test", "Finished test"))
+ {
+ using (DisposableTimer.TraceDuration("Starting FindClassesOfType", "Finished FindClassesOfType"))
+ {
+ for (var i = 0; i < 1000; i++)
+ {
+ Assert.Greater(TypeFinder.FindClassesOfType(_assemblies).Count(), 0);
+ }
+ }
+ using (DisposableTimer.TraceDuration("Starting FindClassesOfTypeWithAttribute", "Finished FindClassesOfTypeWithAttribute"))
+ {
+ for (var i = 0; i < 1000; i++)
+ {
+ Assert.Greater(TypeFinder.FindClassesOfTypeWithAttribute(_assemblies).Count(), 0);
+ }
+ }
+ using (DisposableTimer.TraceDuration("Starting FindClassesWithAttribute", "Finished FindClassesWithAttribute"))
+ {
+ for (var i = 0; i < 1000; i++)
+ {
+ Assert.Greater(TypeFinder.FindClassesWithAttribute(_assemblies).Count(), 0);
+ }
+ }
+ }
+
+ }
+
+ public class MyTag : ITag
+ {
+ public int Id { get; private set; }
+ public string TagCaption { get; private set; }
+ public string Group { get; private set; }
+ }
+
+ public class MySuperTag : MyTag
+ {
+
+ }
+
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public class MyTestAttribute : Attribute
+ {
+
+ }
+
+ public abstract class TestEditor
+ {
+
+ }
+
+ [MyTest]
+ public class BenchmarkTestEditor : TestEditor
+ {
+
+ }
+
+ [MyTest]
+ public class MyOtherTestEditor : TestEditor
+ {
+
+ }
+
+ //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 LocalFilteredAssemblyCache = new ConcurrentBag();
+ private static readonly ReaderWriterLockSlim LocalFilteredAssemblyCacheLocker = new ReaderWriterLockSlim();
+ private static ReadOnlyCollection _allAssemblies = null;
+ private static ReadOnlyCollection _binFolderAssemblies = null;
+ private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
+
+ ///
+ /// 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
+ ///
+ ///
+ /// 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
+ ///
+ internal static IEnumerable GetAllAssemblies()
+ {
+ if (_allAssemblies == null)
+ {
+ using (new WriteLock(Locker))
+ {
+ List assemblies = null;
+ try
+ {
+ var isHosted = HttpContext.Current != null;
+
+ try
+ {
+ if (isHosted)
+ {
+ assemblies = new List(BuildManager.GetReferencedAssemblies().Cast());
+ }
+ }
+ 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();
+ 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(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())))
+ {
+ 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(assemblies);
+
+ }
+ catch (InvalidOperationException e)
+ {
+ if (!(e.InnerException is SecurityException))
+ throw;
+
+ _binFolderAssemblies = _allAssemblies;
+ }
+ }
+ }
+
+ return _allAssemblies;
+ }
+
+ ///
+ /// Returns only assemblies found in the bin folder that have been loaded into the app domain.
+ ///
+ ///
+ ///
+ /// This will be used if we implement App_Plugins from Umbraco v5 but currently it is not used.
+ ///
+ internal static IEnumerable 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();
+ var binFolderAssemblies = new List();
+
+ 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(binFolderAssemblies);
+ }
+ }
+ return _binFolderAssemblies;
+ }
+
+ ///
+ /// 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.
+ ///
+ ///
+ ///
+ internal static IEnumerable GetAssembliesWithKnownExclusions(
+ IEnumerable excludeFromResults = null)
+ {
+ if (LocalFilteredAssemblyCache.Any()) return LocalFilteredAssemblyCache;
+ using (new WriteLock(LocalFilteredAssemblyCacheLocker))
+ {
+ var assemblies = GetFilteredAssemblies(excludeFromResults, KnownAssemblyExclusionFilter);
+ assemblies.ForEach(LocalFilteredAssemblyCache.Add);
+ }
+ return LocalFilteredAssemblyCache;
+ }
+
+ ///
+ /// Return a list of found local Assemblies and exluding the ones passed in and excluding the exclusion list filter
+ ///
+ ///
+ ///
+ ///
+ private static IEnumerable GetFilteredAssemblies(
+ IEnumerable excludeFromResults = null,
+ string[] exclusionFilter = null)
+ {
+ if (excludeFromResults == null)
+ excludeFromResults = new List();
+ if (exclusionFilter == null)
+ exclusionFilter = new string[] { };
+
+ return GetAllAssemblies()
+ .Where(x => !excludeFromResults.Contains(x)
+ && !x.GlobalAssemblyCache
+ && !exclusionFilter.Any(f => x.FullName.StartsWith(f)));
+ }
+
+ ///
+ /// this is our assembly filter to filter out known types that def dont contain types we'd like to find or plugins
+ ///
+ ///
+ /// 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
+ ///
+ internal static readonly string[] KnownAssemblyExclusionFilter = new[]
+ {
+ "mscorlib,",
+ "System.",
+ "Antlr3.",
+ "Autofac.",
+ "Autofac,",
+ "Castle.",
+ "ClientDependency.",
+ "DataAnnotationsExtensions.",
+ "DataAnnotationsExtensions,",
+ "Dynamic,",
+ "HtmlDiff,",
+ "Iesi.Collections,",
+ "log4net,",
+ "Microsoft.",
+ "Newtonsoft.",
+ "NHibernate.",
+ "NHibernate,",
+ "NuGet.",
+ "RouteDebugger,",
+ "SqlCE4Umbraco,",
+ "umbraco.datalayer,",
+ "umbraco.interfaces,",
+ "umbraco.providers,",
+ "Umbraco.Web.UI,",
+ "umbraco.webservices",
+ "Lucene.",
+ "Examine,",
+ "Examine.",
+ "ServiceStack.",
+ "MySql.",
+ "HtmlAgilityPack.",
+ "TidyNet.",
+ "ICSharpCode.",
+ "CookComputing.",
+ /* Mono */
+ "MonoDevelop.NUnit"
+ };
+
+ public static IEnumerable FindClassesOfTypeWithAttribute()
+ where TAttribute : Attribute
+ {
+ return FindClassesOfTypeWithAttribute(GetAssembliesWithKnownExclusions(), true);
+ }
+
+ public static IEnumerable FindClassesOfTypeWithAttribute(IEnumerable assemblies)
+ where TAttribute : Attribute
+ {
+ return FindClassesOfTypeWithAttribute(assemblies, true);
+ }
+
+ public static IEnumerable FindClassesOfTypeWithAttribute(IEnumerable assemblies, bool onlyConcreteClasses)
+ where TAttribute : Attribute
+ {
+ if (assemblies == null) throw new ArgumentNullException("assemblies");
+
+ var l = new List();
+ foreach (var a in assemblies)
+ {
+ var types = from t in GetTypesWithFormattedException(a)
+ where !t.IsInterface
+ && typeof(T).IsAssignableFrom(t)
+ && t.GetCustomAttributes(false).Any()
+ && (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract))
+ select t;
+ l.AddRange(types);
+ }
+
+ return l;
+ }
+
+ ///
+ /// Searches all filtered local assemblies specified for classes of the type passed in.
+ ///
+ ///
+ ///
+ public static IEnumerable FindClassesOfType()
+ {
+ return FindClassesOfType(GetAssembliesWithKnownExclusions(), true);
+ }
+
+ ///
+ /// Returns all types found of in the assemblies specified of type T
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IEnumerable FindClassesOfType(IEnumerable