2012-08-14 12:03:34 +06:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
2014-03-12 14:16:52 +11:00
|
|
|
using System.Threading;
|
2015-01-16 15:47:44 +11:00
|
|
|
using Umbraco.Core.Logging;
|
2012-08-14 12:03:34 +06:00
|
|
|
using umbraco.interfaces;
|
|
|
|
|
|
2013-01-29 09:45:12 +06:00
|
|
|
namespace Umbraco.Core.ObjectResolution
|
2012-08-14 12:03:34 +06:00
|
|
|
{
|
2016-11-25 10:35:36 +01:00
|
|
|
/// <summary>
|
2012-08-14 12:03:34 +06:00
|
|
|
/// A resolver to return all IApplicationEvents objects
|
|
|
|
|
/// </summary>
|
2014-03-12 14:16:52 +11:00
|
|
|
/// <remarks>
|
|
|
|
|
/// This is disposable because after the app has started it should be disposed to release any memory being occupied by instances.
|
|
|
|
|
/// </remarks>
|
2016-11-24 11:20:01 +01:00
|
|
|
public sealed class ApplicationEventsResolver : ManyObjectsResolverBase<ApplicationEventsResolver, IApplicationEventHandler>, IDisposable
|
2012-08-14 12:03:34 +06:00
|
|
|
{
|
2013-02-14 23:05:58 +06:00
|
|
|
private readonly LegacyStartupHandlerResolver _legacyResolver;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2015-01-16 15:47:44 +11:00
|
|
|
/// Constructor
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="logger"></param>
|
|
|
|
|
/// <param name="applicationEventHandlers"></param>
|
2016-11-24 18:13:05 +01:00
|
|
|
/// <param name="serviceProvider"></param>
|
2015-01-16 15:47:44 +11:00
|
|
|
internal ApplicationEventsResolver(IServiceProvider serviceProvider, ILogger logger, IEnumerable<Type> applicationEventHandlers)
|
|
|
|
|
: base(serviceProvider, logger, applicationEventHandlers)
|
2012-08-14 12:03:34 +06:00
|
|
|
{
|
2013-02-14 23:05:58 +06:00
|
|
|
//create the legacy resolver and only include the legacy types
|
|
|
|
|
_legacyResolver = new LegacyStartupHandlerResolver(
|
2015-07-22 12:44:29 +02:00
|
|
|
serviceProvider, logger,
|
2016-11-24 11:20:01 +01:00
|
|
|
applicationEventHandlers.Where(x => TypeHelper.IsTypeAssignableFrom<IApplicationEventHandler>(x) == false));
|
2012-08-14 12:03:34 +06:00
|
|
|
}
|
|
|
|
|
|
2013-02-14 23:05:58 +06:00
|
|
|
/// <summary>
|
2016-11-24 18:13:05 +01:00
|
|
|
/// Override in order to only return types of IApplicationEventHandler and above,
|
2013-02-14 23:05:58 +06:00
|
|
|
/// do not include the legacy types of IApplicationStartupHandler
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected override IEnumerable<Type> InstanceTypes
|
|
|
|
|
{
|
|
|
|
|
get { return base.InstanceTypes.Where(TypeHelper.IsTypeAssignableFrom<IApplicationEventHandler>); }
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-24 11:20:01 +01:00
|
|
|
private List<IApplicationEventHandler> _orderedAndFiltered;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the <see cref="IApplicationEventHandler"/> implementations.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public IEnumerable<IApplicationEventHandler> ApplicationEventHandlers
|
2012-08-14 12:03:34 +06:00
|
|
|
{
|
2016-11-24 11:20:01 +01:00
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
if (_orderedAndFiltered == null)
|
|
|
|
|
{
|
2016-11-25 14:34:04 +01:00
|
|
|
_resolved = true;
|
2016-11-25 10:35:36 +01:00
|
|
|
_orderedAndFiltered = GetSortedValues().ToList();
|
|
|
|
|
OnCollectionResolved(_orderedAndFiltered);
|
2016-11-24 11:20:01 +01:00
|
|
|
}
|
|
|
|
|
return _orderedAndFiltered;
|
|
|
|
|
}
|
2012-08-14 12:03:34 +06:00
|
|
|
}
|
2016-11-25 14:14:43 +01:00
|
|
|
|
2016-11-25 14:34:04 +01:00
|
|
|
/// <summary>
|
|
|
|
|
/// A delegate that can be set in the pre-boot phase in order to filter or re-order the event handler collection
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// This can be set on startup in the pre-boot process in either a custom boot manager or global.asax (UmbracoApplication)
|
|
|
|
|
/// </remarks>
|
|
|
|
|
public Action<IList<IApplicationEventHandler>> FilterCollection
|
|
|
|
|
{
|
|
|
|
|
get { return _filterCollection; }
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (_resolved)
|
|
|
|
|
throw new InvalidOperationException("Cannot set the FilterCollection delegate once the ApplicationEventHandlers are resolved");
|
2016-11-25 14:14:43 +01:00
|
|
|
|
2016-11-25 14:34:04 +01:00
|
|
|
_filterCollection = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Allow any filters to be applied to the event handler list
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="handlers"></param>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// This allows custom logic to execute in order to filter or re-order the event handlers prior to executing,
|
|
|
|
|
/// however this also ensures that any core handlers are executed first to ensure the stabiliy of Umbraco.
|
|
|
|
|
/// </remarks>
|
|
|
|
|
private void OnCollectionResolved(List<IApplicationEventHandler> handlers)
|
2016-11-25 10:35:36 +01:00
|
|
|
{
|
2016-11-25 14:14:43 +01:00
|
|
|
if (FilterCollection == null) return;
|
|
|
|
|
|
|
|
|
|
FilterCollection(handlers);
|
2012-08-14 12:03:34 +06:00
|
|
|
|
2016-11-25 10:35:36 +01:00
|
|
|
//find all of the core handlers and their weight, remove them from the main list
|
|
|
|
|
var coreItems = new List<Tuple<IApplicationEventHandler, int>>();
|
|
|
|
|
foreach (var handler in handlers.ToArray())
|
|
|
|
|
{
|
|
|
|
|
//Yuck, but not sure what else we can do
|
|
|
|
|
if (
|
|
|
|
|
handler.GetType().Assembly.FullName.StartsWith("Umbraco.", StringComparison.OrdinalIgnoreCase)
|
|
|
|
|
|| handler.GetType().Assembly.FullName.StartsWith("Concorde."))
|
|
|
|
|
{
|
|
|
|
|
coreItems.Add(new Tuple<IApplicationEventHandler, int>(handler, GetObjectWeight(handler)));
|
|
|
|
|
handlers.Remove(handler);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-11-24 11:20:01 +01:00
|
|
|
|
2016-11-25 10:35:36 +01:00
|
|
|
//re-add the core handlers to the beginning of the list ordered by their weight
|
|
|
|
|
foreach (var coreHandler in coreItems.OrderBy(x => x.Item2))
|
|
|
|
|
{
|
|
|
|
|
handlers.Insert(0, coreHandler.Item1);
|
|
|
|
|
}
|
2016-11-24 11:20:01 +01:00
|
|
|
}
|
2016-11-24 18:13:05 +01:00
|
|
|
|
2013-02-14 23:05:58 +06:00
|
|
|
/// <summary>
|
|
|
|
|
/// Create instances of all of the legacy startup handlers
|
|
|
|
|
/// </summary>
|
2013-04-16 04:27:03 -02:00
|
|
|
public void InstantiateLegacyStartupHandlers()
|
2013-02-14 23:05:58 +06:00
|
|
|
{
|
|
|
|
|
//this will instantiate them all
|
|
|
|
|
var handlers = _legacyResolver.LegacyStartupHandlers;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-13 10:59:21 +05:00
|
|
|
protected override bool SupportsClear
|
2012-08-14 12:03:34 +06:00
|
|
|
{
|
2014-03-12 14:16:52 +11:00
|
|
|
get { return false; }
|
2016-11-24 18:13:05 +01:00
|
|
|
}
|
2012-08-14 12:03:34 +06:00
|
|
|
|
2012-10-13 10:59:21 +05:00
|
|
|
protected override bool SupportsInsert
|
2012-08-14 12:03:34 +06:00
|
|
|
{
|
2016-11-24 18:13:05 +01:00
|
|
|
get { return false; }
|
2012-08-14 12:03:34 +06:00
|
|
|
}
|
|
|
|
|
|
2014-03-12 14:16:52 +11:00
|
|
|
private class LegacyStartupHandlerResolver : ManyObjectsResolverBase<ApplicationEventsResolver, IApplicationStartupHandler>, IDisposable
|
2013-02-14 23:05:58 +06:00
|
|
|
{
|
2015-07-22 12:44:29 +02:00
|
|
|
internal LegacyStartupHandlerResolver(IServiceProvider serviceProvider, ILogger logger, IEnumerable<Type> legacyStartupHandlers)
|
|
|
|
|
: base(serviceProvider, logger, legacyStartupHandlers)
|
2013-02-14 23:05:58 +06:00
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IEnumerable<IApplicationStartupHandler> LegacyStartupHandlers
|
|
|
|
|
{
|
|
|
|
|
get { return Values; }
|
|
|
|
|
}
|
2013-02-14 23:14:43 +06:00
|
|
|
|
2014-03-12 14:16:52 +11:00
|
|
|
public void Dispose()
|
|
|
|
|
{
|
2014-03-12 18:00:00 +11:00
|
|
|
ResetCollections();
|
2014-03-12 14:16:52 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool _disposed;
|
|
|
|
|
private readonly ReaderWriterLockSlim _disposalLocker = new ReaderWriterLockSlim();
|
2016-11-25 14:34:04 +01:00
|
|
|
private Action<IList<IApplicationEventHandler>> _filterCollection;
|
|
|
|
|
private bool _resolved = false;
|
2014-03-12 14:16:52 +11:00
|
|
|
|
2016-11-25 14:34:04 +01:00
|
|
|
/// <summary>
|
2014-03-12 14:16:52 +11:00
|
|
|
/// Gets a value indicating whether this instance is disposed.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <value>
|
|
|
|
|
/// <c>true</c> if this instance is disposed; otherwise, <c>false</c>.
|
|
|
|
|
/// </value>
|
|
|
|
|
public bool IsDisposed
|
|
|
|
|
{
|
|
|
|
|
get { return _disposed; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <filterpriority>2</filterpriority>
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
Dispose(true);
|
|
|
|
|
|
|
|
|
|
// Use SupressFinalize in case a subclass of this type implements a finalizer.
|
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~ApplicationEventsResolver()
|
|
|
|
|
{
|
|
|
|
|
// Run dispose but let the class know it was due to the finalizer running.
|
|
|
|
|
Dispose(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Dispose(bool disposing)
|
|
|
|
|
{
|
|
|
|
|
// Only operate if we haven't already disposed
|
|
|
|
|
if (IsDisposed || disposing == false) return;
|
|
|
|
|
|
|
|
|
|
using (new WriteLock(_disposalLocker))
|
|
|
|
|
{
|
|
|
|
|
// Check again now we're inside the lock
|
|
|
|
|
if (IsDisposed) return;
|
|
|
|
|
|
|
|
|
|
// Call to actually release resources. This method is only
|
|
|
|
|
// kept separate so that the entire disposal logic can be used as a VS snippet
|
|
|
|
|
DisposeResources();
|
|
|
|
|
|
|
|
|
|
// Indicate that the instance has been disposed.
|
|
|
|
|
_disposed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Clear out all of the instances, we don't want them hanging around and cluttering up memory
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void DisposeResources()
|
|
|
|
|
{
|
|
|
|
|
_legacyResolver.Dispose();
|
2014-03-12 18:00:00 +11:00
|
|
|
ResetCollections();
|
2016-11-24 11:20:01 +01:00
|
|
|
_orderedAndFiltered.Clear();
|
2016-11-25 10:35:36 +01:00
|
|
|
_orderedAndFiltered = null;
|
2014-03-12 14:16:52 +11:00
|
|
|
}
|
2016-11-24 11:20:01 +01:00
|
|
|
}
|
2012-08-14 12:03:34 +06:00
|
|
|
}
|