using System; using System.Collections.Generic; using System.Linq; using System.Threading; using Umbraco.Core.Logging; using umbraco.interfaces; namespace Umbraco.Core.ObjectResolution { /// /// A resolver to return all IApplicationEvents objects /// /// /// This is disposable because after the app has started it should be disposed to release any memory being occupied by instances. /// public sealed class ApplicationEventsResolver : ManyObjectsResolverBase, IDisposable { private readonly LegacyStartupHandlerResolver _legacyResolver; /// /// Constructor /// /// /// /// internal ApplicationEventsResolver(IServiceProvider serviceProvider, ILogger logger, IEnumerable applicationEventHandlers) : base(serviceProvider, logger, applicationEventHandlers) { //create the legacy resolver and only include the legacy types _legacyResolver = new LegacyStartupHandlerResolver( serviceProvider, logger, applicationEventHandlers.Where(x => TypeHelper.IsTypeAssignableFrom(x) == false)); } /// /// Override in order to only return types of IApplicationEventHandler and above, /// do not include the legacy types of IApplicationStartupHandler /// protected override IEnumerable InstanceTypes { get { return base.InstanceTypes.Where(TypeHelper.IsTypeAssignableFrom); } } private List _orderedAndFiltered; /// /// Gets the implementations. /// public IEnumerable ApplicationEventHandlers { get { if (_orderedAndFiltered == null) { _orderedAndFiltered = GetSortedValues().ToList(); //raise event so the collection can be modified OnCollectionResolved(new ApplicationEventsEventArgs(_orderedAndFiltered)); } return _orderedAndFiltered; } } public event EventHandler CollectionResolved; private void OnCollectionResolved(ApplicationEventsEventArgs e) { var handler = CollectionResolved; if (handler != null) handler(this, e); } /// /// Create instances of all of the legacy startup handlers /// public void InstantiateLegacyStartupHandlers() { //this will instantiate them all var handlers = _legacyResolver.LegacyStartupHandlers; } protected override bool SupportsClear { get { return false; } } protected override bool SupportsInsert { get { return false; } } private class LegacyStartupHandlerResolver : ManyObjectsResolverBase, IDisposable { internal LegacyStartupHandlerResolver(IServiceProvider serviceProvider, ILogger logger, IEnumerable legacyStartupHandlers) : base(serviceProvider, logger, legacyStartupHandlers) { } public IEnumerable LegacyStartupHandlers { get { return Values; } } public void Dispose() { ResetCollections(); } } private bool _disposed; private readonly ReaderWriterLockSlim _disposalLocker = new ReaderWriterLockSlim(); /// /// Gets a value indicating whether this instance is disposed. /// /// /// true if this instance is disposed; otherwise, false. /// public bool IsDisposed { get { return _disposed; } } /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// /// 2 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; } } /// /// Clear out all of the instances, we don't want them hanging around and cluttering up memory /// private void DisposeResources() { _legacyResolver.Dispose(); ResetCollections(); _orderedAndFiltered.Clear(); _orderedAndFiltered = null; //Clear event handlers CollectionResolved = null; } } }