diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs
index b322fb5290..6e4b94ca44 100644
--- a/src/SolutionInfo.cs
+++ b/src/SolutionInfo.cs
@@ -12,4 +12,4 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.6.0")]
-[assembly: AssemblyInformationalVersion("7.6.0-alpha016")]
\ No newline at end of file
+[assembly: AssemblyInformationalVersion("7.6.0-alpha019")]
\ No newline at end of file
diff --git a/src/Umbraco.Core/Configuration/UmbracoVersion.cs b/src/Umbraco.Core/Configuration/UmbracoVersion.cs
index 09f6cd8b84..adde8ca8cd 100644
--- a/src/Umbraco.Core/Configuration/UmbracoVersion.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoVersion.cs
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Configuration
/// Gets the version comment (like beta or RC).
///
/// The version comment.
- public static string CurrentComment { get { return "alpha016"; } }
+ public static string CurrentComment { get { return "alpha019"; } }
// Get the version of the umbraco.dll by looking at a class in that dll
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
diff --git a/src/Umbraco.Core/Logging/DebugDiagnosticsLogger.cs b/src/Umbraco.Core/Logging/DebugDiagnosticsLogger.cs
index c1b3306129..f5ae689da9 100644
--- a/src/Umbraco.Core/Logging/DebugDiagnosticsLogger.cs
+++ b/src/Umbraco.Core/Logging/DebugDiagnosticsLogger.cs
@@ -3,7 +3,11 @@ using System.Linq;
namespace Umbraco.Core.Logging
{
- internal class DebugDiagnosticsLogger : ILogger
+ ///
+ /// Implements on top of System.Diagnostics.Debug.
+ ///
+ /// Useful for tests.
+ public class DebugDiagnosticsLogger : ILogger
{
public void Error(Type callingType, string message, Exception exception)
{
diff --git a/src/Umbraco.Core/MainDom.cs b/src/Umbraco.Core/MainDom.cs
index 9ded022195..52dbb21f21 100644
--- a/src/Umbraco.Core/MainDom.cs
+++ b/src/Umbraco.Core/MainDom.cs
@@ -11,8 +11,16 @@ using Umbraco.Core.ObjectResolution;
namespace Umbraco.Core
{
- // represents the main domain
- class MainDom : IRegisteredObject
+ ///
+ /// Represents the main AppDomain running for a given application.
+ ///
+ ///
+ /// There can be only one "main" AppDomain running for a given application at a time.
+ /// When an AppDomain starts, it tries to acquire the main domain status.
+ /// When an AppDomain stops (eg the application is restarting) it should release the main domain status.
+ /// It is possible to register against the MainDom and be notified when it is released.
+ ///
+ internal class MainDom : IRegisteredObject
{
#region Vars
@@ -34,16 +42,26 @@ namespace Umbraco.Core
private volatile bool _signaled; // we have been signaled
// actions to run before releasing the main domain
- private readonly SortedList _callbacks = new SortedList();
+ private readonly SortedList _callbacks = new SortedList(new WeightComparer());
private const int LockTimeoutMilliseconds = 90000; // (1.5 * 60 * 1000) == 1 min 30 seconds
+ private class WeightComparer : IComparer
+ {
+ public int Compare(int x, int y)
+ {
+ var result = x.CompareTo(y);
+ // return "equal" as "greater than"
+ return result == 0 ? 1 : result;
+ }
+ }
+
#endregion
#region Ctor
// initializes a new instance of MainDom
- public MainDom(ILogger logger)
+ internal MainDom(ILogger logger)
{
_logger = logger;
@@ -73,13 +91,26 @@ namespace Umbraco.Core
#endregion
- // register a main domain consumer
+ ///
+ /// Registers a resource that requires the current AppDomain to be the main domain to function.
+ ///
+ /// An action to execute before the AppDomain releases the main domain status.
+ /// An optional weight (lower goes first).
+ /// A value indicating whether it was possible to register.
public bool Register(Action release, int weight = 100)
{
return Register(null, release, weight);
}
- // register a main domain consumer
+ ///
+ /// Registers a resource that requires the current AppDomain to be the main domain to function.
+ ///
+ /// An action to execute when registering.
+ /// An action to execute before the AppDomain releases the main domain status.
+ /// An optional weight (lower goes first).
+ /// A value indicating whether it was possible to register.
+ /// If registering is successful, then the action
+ /// is guaranteed to execute before the AppDomain releases the main domain status.
public bool Register(Action install, Action release, int weight = 100)
{
lock (_locko)
@@ -135,7 +166,7 @@ namespace Umbraco.Core
}
// acquires the main domain
- public bool Acquire()
+ internal bool Acquire()
{
lock (_locko) // we don't want the hosting environment to interfere by signaling
{
@@ -186,7 +217,7 @@ namespace Umbraco.Core
}
// IRegisteredObject
- public void Stop(bool immediate)
+ void IRegisteredObject.Stop(bool immediate)
{
try
{
diff --git a/src/Umbraco.Web/Scheduling/BackgroundTaskRunner.cs b/src/Umbraco.Web/Scheduling/BackgroundTaskRunner.cs
index d63fbb4606..b67c2c08ac 100644
--- a/src/Umbraco.Web/Scheduling/BackgroundTaskRunner.cs
+++ b/src/Umbraco.Web/Scheduling/BackgroundTaskRunner.cs
@@ -3,13 +3,17 @@ using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Hosting;
+using Umbraco.Core;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
namespace Umbraco.Web.Scheduling
{
- // exists for logging purposes
- internal class BackgroundTaskRunner
+ ///
+ /// Manages a queue of tasks and runs them in the background.
+ ///
+ /// This class exists for logging purposes - the one you want to use is BackgroundTaskRunner{T}.
+ public abstract class BackgroundTaskRunner
{ }
///
@@ -18,7 +22,7 @@ namespace Umbraco.Web.Scheduling
/// The type of the managed tasks.
/// The task runner is web-aware and will ensure that it shuts down correctly when the AppDomain
/// shuts down (ie is unloaded).
- internal class BackgroundTaskRunner : BackgroundTaskRunner, IBackgroundTaskRunner
+ public class BackgroundTaskRunner : BackgroundTaskRunner, IBackgroundTaskRunner
where T : class, IBackgroundTask
{
private readonly string _logPrefix;
@@ -43,10 +47,10 @@ namespace Umbraco.Web.Scheduling
private bool _terminated; // remember we've terminated
private TaskCompletionSource _terminatedSource; // awaitable source
- internal event TypedEventHandler, TaskEventArgs> TaskError;
- internal event TypedEventHandler, TaskEventArgs> TaskStarting;
- internal event TypedEventHandler, TaskEventArgs> TaskCompleted;
- internal event TypedEventHandler, TaskEventArgs> TaskCancelled;
+ public event TypedEventHandler, TaskEventArgs> TaskError;
+ public event TypedEventHandler, TaskEventArgs> TaskStarting;
+ public event TypedEventHandler, TaskEventArgs> TaskCompleted;
+ public event TypedEventHandler, TaskEventArgs> TaskCancelled;
// triggers when the runner stops (but could start again if a task is added to it)
internal event TypedEventHandler, EventArgs> Stopped;
@@ -60,26 +64,33 @@ namespace Umbraco.Web.Scheduling
///
/// Initializes a new instance of the class.
///
- public BackgroundTaskRunner(ILogger logger)
- : this(typeof (T).FullName, new BackgroundTaskRunnerOptions(), logger)
+ /// A logger.
+ /// An optional action to execute when the main domain status is aquired.
+ /// An optional action to execute when the main domain status is released.
+ public BackgroundTaskRunner(ILogger logger, Action mainDomInstall = null, Action mainDomRelease = null)
+ : this(typeof (T).FullName, new BackgroundTaskRunnerOptions(), logger, mainDomInstall, mainDomRelease)
{ }
///
/// Initializes a new instance of the class.
///
/// The name of the runner.
- ///
- public BackgroundTaskRunner(string name, ILogger logger)
- : this(name, new BackgroundTaskRunnerOptions(), logger)
+ /// A logger.
+ /// An optional action to execute when the main domain status is aquired.
+ /// An optional action to execute when the main domain status is released.
+ public BackgroundTaskRunner(string name, ILogger logger, Action mainDomInstall = null, Action mainDomRelease = null)
+ : this(name, new BackgroundTaskRunnerOptions(), logger, mainDomInstall, mainDomRelease)
{ }
///
/// Initializes a new instance of the class with a set of options.
///
/// The set of options.
- ///
- public BackgroundTaskRunner(BackgroundTaskRunnerOptions options, ILogger logger)
- : this(typeof (T).FullName, options, logger)
+ /// A logger.
+ /// An optional action to execute when the main domain status is aquired.
+ /// An optional action to execute when the main domain status is released.
+ public BackgroundTaskRunner(BackgroundTaskRunnerOptions options, ILogger logger, Action mainDomInstall = null, Action mainDomRelease = null)
+ : this(typeof (T).FullName, options, logger, mainDomInstall, mainDomRelease)
{ }
///
@@ -87,8 +98,10 @@ namespace Umbraco.Web.Scheduling
///
/// The name of the runner.
/// The set of options.
- ///
- public BackgroundTaskRunner(string name, BackgroundTaskRunnerOptions options, ILogger logger)
+ /// A logger.
+ /// An optional action to execute when the main domain status is aquired.
+ /// An optional action to execute when the main domain status is released.
+ public BackgroundTaskRunner(string name, BackgroundTaskRunnerOptions options, ILogger logger, Action mainDomInstall = null, Action mainDomRelease = null)
{
if (options == null) throw new ArgumentNullException("options");
if (logger == null) throw new ArgumentNullException("logger");
@@ -99,7 +112,15 @@ namespace Umbraco.Web.Scheduling
if (options.Hosted)
HostingEnvironment.RegisterObject(this);
- if (options.AutoStart)
+ if (mainDomRelease != null)
+ {
+ var mainDom = ApplicationContext.Current.MainDom;
+ var reg = mainDom == null || ApplicationContext.Current.MainDom.Register(mainDomInstall, mainDomRelease);
+ if (reg == false)
+ _isCompleted = _terminated = true;
+ }
+
+ if (options.AutoStart && _terminated == false)
StartUp();
}
diff --git a/src/Umbraco.Web/Scheduling/BackgroundTaskRunnerOptions.cs b/src/Umbraco.Web/Scheduling/BackgroundTaskRunnerOptions.cs
index 55df42d3b7..28c814db24 100644
--- a/src/Umbraco.Web/Scheduling/BackgroundTaskRunnerOptions.cs
+++ b/src/Umbraco.Web/Scheduling/BackgroundTaskRunnerOptions.cs
@@ -3,7 +3,7 @@ namespace Umbraco.Web.Scheduling
///
/// Provides options to the class.
///
- internal class BackgroundTaskRunnerOptions
+ public class BackgroundTaskRunnerOptions
{
//TODO: Could add options for using a stack vs queue if required
diff --git a/src/Umbraco.Web/Scheduling/TaskEventArgs.cs b/src/Umbraco.Web/Scheduling/TaskEventArgs.cs
index 27e5174616..5e83b14231 100644
--- a/src/Umbraco.Web/Scheduling/TaskEventArgs.cs
+++ b/src/Umbraco.Web/Scheduling/TaskEventArgs.cs
@@ -2,21 +2,41 @@
namespace Umbraco.Web.Scheduling
{
- internal class TaskEventArgs : EventArgs
+ ///
+ /// Provides arguments for task runner events.
+ ///
+ /// The type of the task.
+ public class TaskEventArgs : EventArgs
where T : IBackgroundTask
{
- public T Task { get; private set; }
- public Exception Exception { get; private set; }
-
+ ///
+ /// Initializes a new instance of the class with a task.
+ ///
+ /// The task.
public TaskEventArgs(T task)
{
Task = task;
}
+ ///
+ /// Initializes a new instance of the class with a task and an exception.
+ ///
+ /// The task.
+ /// An exception.
public TaskEventArgs(T task, Exception exception)
{
Task = task;
Exception = exception;
}
+
+ ///
+ /// Gets or sets the task.
+ ///
+ public T Task { get; private set; }
+
+ ///
+ /// Gets or sets the exception.
+ ///
+ public Exception Exception { get; private set; }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Scheduling/ThreadingTaskImmutable.cs b/src/Umbraco.Web/Scheduling/ThreadingTaskImmutable.cs
index e8ccbeac0e..1bb5fcbf41 100644
--- a/src/Umbraco.Web/Scheduling/ThreadingTaskImmutable.cs
+++ b/src/Umbraco.Web/Scheduling/ThreadingTaskImmutable.cs
@@ -5,10 +5,10 @@ using System.Threading.Tasks;
namespace Umbraco.Web.Scheduling
{
///
- /// Wraps a Task within an object that gives access to its GetAwaiter method and Status
+ /// Wraps a within an object that gives access to its GetAwaiter method and Status
/// property while ensuring that it cannot be modified in any way.
///
- internal class ThreadingTaskImmutable
+ public class ThreadingTaskImmutable
{
private readonly Task _task;