Components Initialize and Terminate
This commit is contained in:
@@ -23,7 +23,10 @@ namespace Umbraco.Core.Components
|
||||
_auditService = auditService;
|
||||
_userService = userService;
|
||||
_entityService = entityService;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
UserService.SavedUserGroup += OnSavedUserGroupWithUsers;
|
||||
|
||||
UserService.SavedUser += OnSavedUser;
|
||||
@@ -37,6 +40,9 @@ namespace Umbraco.Core.Components
|
||||
MemberService.Exported += OnMemberExported;
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
|
||||
private IUser CurrentPerformingUser
|
||||
{
|
||||
get
|
||||
|
||||
@@ -20,6 +20,21 @@ namespace Umbraco.Core.Components
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
using (_logger.DebugDuration<ComponentCollection>($"Initializing. (log components when >{LogThresholdMilliseconds}ms)", "Initialized."))
|
||||
{
|
||||
foreach (var component in this.Reverse()) // terminate components in reverse order
|
||||
{
|
||||
var componentType = component.GetType();
|
||||
using (_logger.DebugDuration<ComponentCollection>($"Initializing {componentType.FullName}.", $"Initialized {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds))
|
||||
{
|
||||
component.Initialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
using (_logger.DebugDuration<ComponentCollection>($"Terminating. (log components when >{LogThresholdMilliseconds}ms)", "Terminated."))
|
||||
@@ -29,6 +44,7 @@ namespace Umbraco.Core.Components
|
||||
var componentType = component.GetType();
|
||||
using (_logger.DebugDuration<ComponentCollection>($"Terminating {componentType.FullName}.", $"Terminated {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds))
|
||||
{
|
||||
component.Terminate();
|
||||
component.DisposeIfDisposable();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,21 @@
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Components are created by DI and therefore must have a public constructor.</para>
|
||||
/// <para>All components which are also disposable, will be disposed in reverse
|
||||
/// order, when Umbraco terminates.</para>
|
||||
/// <para>All components are terminated in reverse order when Umbraco terminates, and
|
||||
/// disposable components are disposed.</para>
|
||||
/// <para>The Dispose method may be invoked more than once, and components
|
||||
/// should ensure they support this.</para>
|
||||
/// </remarks>
|
||||
public interface IComponent
|
||||
{ }
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the component.
|
||||
/// </summary>
|
||||
void Initialize();
|
||||
|
||||
/// <summary>
|
||||
/// Terminates the component.
|
||||
/// </summary>
|
||||
void Terminate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,28 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Manifest;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
public sealed class ManifestWatcherComponent : IComponent, IDisposable
|
||||
public sealed class ManifestWatcherComponent : IComponent
|
||||
{
|
||||
private readonly IRuntimeState _runtimeState;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
// if configured and in debug mode, a ManifestWatcher watches App_Plugins folders for
|
||||
// package.manifest chances and restarts the application on any change
|
||||
private ManifestWatcher _mw;
|
||||
|
||||
public ManifestWatcherComponent(IRuntimeState runtimeState, ILogger logger)
|
||||
{
|
||||
if (runtimeState.Debug == false) return;
|
||||
_runtimeState = runtimeState;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
if (_runtimeState.Debug == false) return;
|
||||
|
||||
//if (ApplicationContext.Current.IsConfigured == false || GlobalSettings.DebugMode == false)
|
||||
// return;
|
||||
@@ -22,11 +30,11 @@ namespace Umbraco.Core.Components
|
||||
var appPlugins = IOHelper.MapPath("~/App_Plugins/");
|
||||
if (Directory.Exists(appPlugins) == false) return;
|
||||
|
||||
_mw = new ManifestWatcher(logger);
|
||||
_mw = new ManifestWatcher(_logger);
|
||||
_mw.Start(Directory.GetDirectories(appPlugins));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
public void Terminate()
|
||||
{
|
||||
if (_mw == null) return;
|
||||
|
||||
|
||||
@@ -8,11 +8,14 @@ namespace Umbraco.Core.Components
|
||||
//TODO: This should just exist in the content service/repo!
|
||||
public sealed class RelateOnCopyComponent : IComponent
|
||||
{
|
||||
public RelateOnCopyComponent()
|
||||
public void Initialize()
|
||||
{
|
||||
ContentService.Copied += ContentServiceCopied;
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
|
||||
private static void ContentServiceCopied(IContentService sender, Events.CopyEventArgs<IContent> e)
|
||||
{
|
||||
if (e.RelateToOriginal == false) return;
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Umbraco.Core.Components
|
||||
{
|
||||
public sealed class RelateOnTrashComponent : IComponent
|
||||
{
|
||||
public RelateOnTrashComponent()
|
||||
public void Initialize()
|
||||
{
|
||||
ContentService.Moved += ContentService_Moved;
|
||||
ContentService.Trashed += ContentService_Trashed;
|
||||
@@ -17,6 +17,9 @@ namespace Umbraco.Core.Components
|
||||
MediaService.Trashed += MediaService_Trashed;
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
|
||||
private static void ContentService_Moved(IContentService sender, MoveEventArgs<IContent> e)
|
||||
{
|
||||
foreach (var item in e.MoveInfoCollection.Where(x => x.OriginalPath.Contains(Constants.System.RecycleBinContent.ToInvariantString())))
|
||||
|
||||
@@ -146,8 +146,9 @@ namespace Umbraco.Core.Runtime
|
||||
// create the factory
|
||||
_factory = Current.Factory = composition.CreateFactory();
|
||||
|
||||
// create the components
|
||||
// create & initialize the components
|
||||
_components = _factory.GetInstance<ComponentCollection>();
|
||||
_components.Initialize();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -7,12 +7,19 @@ namespace Umbraco.Core.Runtime
|
||||
{
|
||||
public class CoreRuntimeComponent : IComponent
|
||||
{
|
||||
private readonly IEnumerable<Profile> _mapperProfiles;
|
||||
|
||||
public CoreRuntimeComponent(IEnumerable<Profile> mapperProfiles)
|
||||
{
|
||||
_mapperProfiles = mapperProfiles;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
// mapper profiles have been registered & are created by the container
|
||||
Mapper.Initialize(configuration =>
|
||||
{
|
||||
foreach (var profile in mapperProfiles)
|
||||
foreach (var profile in _mapperProfiles)
|
||||
configuration.AddProfile(profile);
|
||||
});
|
||||
|
||||
@@ -24,5 +31,8 @@ namespace Umbraco.Core.Runtime
|
||||
IOHelper.EnsurePathExists(SystemDirectories.MvcViews + "/Partials");
|
||||
IOHelper.EnsurePathExists(SystemDirectories.MvcViews + "/MacroPartials");
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@ namespace Umbraco.Tests.Components
|
||||
public class ComponentTests
|
||||
{
|
||||
private static readonly List<Type> Composed = new List<Type>();
|
||||
private static readonly List<string> Initialized = new List<string>();
|
||||
private static readonly List<Type> Initialized = new List<Type>();
|
||||
private static readonly List<Type> Terminated = new List<Type>();
|
||||
|
||||
private static IFactory MockFactory(Action<Mock<IFactory>> setup = null)
|
||||
{
|
||||
@@ -64,13 +65,36 @@ namespace Umbraco.Tests.Components
|
||||
var composition = new Composition(register, MockTypeLoader(), Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
|
||||
var types = TypeArray<Composer1, Composer2, Composer3, Composer4>();
|
||||
var components = new Core.Components.Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
var composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
Composed.Clear();
|
||||
// 2 is Core and requires 4
|
||||
// 3 is User - goes away with RuntimeLevel.Unknown
|
||||
// => reorder components accordingly
|
||||
components.Compose();
|
||||
composers.Compose();
|
||||
AssertTypeArray(TypeArray<Composer1, Composer4, Composer2>(), Composed);
|
||||
|
||||
var factory = MockFactory(m =>
|
||||
{
|
||||
m.Setup(x => x.TryGetInstance(It.Is<Type>(t => t == typeof(ISomeResource)))).Returns(() => new SomeResource());
|
||||
m.Setup(x => x.GetInstance(It.IsAny<Type>())).Returns<Type>((type) =>
|
||||
{
|
||||
if (type == typeof(Composer1)) return new Composer1();
|
||||
if (type == typeof(Composer5)) return new Composer5();
|
||||
if (type == typeof(Component5)) return new Component5(new SomeResource());
|
||||
if (type == typeof(IProfilingLogger)) return new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>());
|
||||
throw new NotSupportedException(type.FullName);
|
||||
});
|
||||
});
|
||||
|
||||
var builder = composition.WithCollectionBuilder<ComponentCollectionBuilder>();
|
||||
builder.RegisterWith(register);
|
||||
var components = builder.CreateCollection(factory);
|
||||
|
||||
Assert.IsEmpty(components);
|
||||
components.Initialize();
|
||||
Assert.IsEmpty(Initialized);
|
||||
components.Terminate();
|
||||
Assert.IsEmpty(Terminated);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -164,6 +188,10 @@ namespace Umbraco.Tests.Components
|
||||
[Test]
|
||||
public void Initialize()
|
||||
{
|
||||
Composed.Clear();
|
||||
Initialized.Clear();
|
||||
Terminated.Clear();
|
||||
|
||||
var register = MockRegister();
|
||||
var factory = MockFactory(m =>
|
||||
{
|
||||
@@ -181,17 +209,22 @@ namespace Umbraco.Tests.Components
|
||||
|
||||
var types = new[] { typeof(Composer1), typeof(Composer5) };
|
||||
var composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
Composed.Clear();
|
||||
Initialized.Clear();
|
||||
|
||||
Assert.IsEmpty(Composed);
|
||||
composers.Compose();
|
||||
AssertTypeArray(TypeArray<Composer1, Composer5>(), Composed);
|
||||
|
||||
var builder = composition.WithCollectionBuilder<ComponentCollectionBuilder>();
|
||||
builder.RegisterWith(register);
|
||||
var components = builder.CreateCollection(factory);
|
||||
Assert.AreEqual(2, Composed.Count);
|
||||
Assert.AreEqual(typeof(Composer1), Composed[0]);
|
||||
Assert.AreEqual(typeof(Composer5), Composed[1]);
|
||||
Assert.AreEqual(1, Initialized.Count);
|
||||
Assert.AreEqual("Umbraco.Tests.Components.ComponentTests+SomeResource", Initialized[0]);
|
||||
|
||||
Assert.IsEmpty(Initialized);
|
||||
components.Initialize();
|
||||
AssertTypeArray(TypeArray<Component5>(), Initialized);
|
||||
|
||||
Assert.IsEmpty(Terminated);
|
||||
components.Terminate();
|
||||
AssertTypeArray(TypeArray<Component5>(), Terminated);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -301,9 +334,6 @@ namespace Umbraco.Tests.Components
|
||||
}
|
||||
}
|
||||
|
||||
public class TestComponentBase : IComponent
|
||||
{ }
|
||||
|
||||
public class Composer1 : TestComposerBase
|
||||
{ }
|
||||
|
||||
@@ -326,11 +356,26 @@ namespace Umbraco.Tests.Components
|
||||
}
|
||||
}
|
||||
|
||||
public class Component5 : IComponent
|
||||
public class TestComponentBase : IComponent
|
||||
{
|
||||
public virtual void Initialize()
|
||||
{
|
||||
Initialized.Add(GetType());
|
||||
}
|
||||
|
||||
public virtual void Terminate()
|
||||
{
|
||||
Terminated.Add(GetType());
|
||||
}
|
||||
}
|
||||
|
||||
public class Component5 : TestComponentBase
|
||||
{
|
||||
private readonly ISomeResource _resource;
|
||||
|
||||
public Component5(ISomeResource resource)
|
||||
{
|
||||
Initialized.Add(resource.GetType().FullName);
|
||||
_resource = resource;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -191,8 +191,7 @@ namespace Umbraco.Tests.Runtimes
|
||||
{
|
||||
// test flags
|
||||
public static bool Ctored;
|
||||
public static bool Initialized1;
|
||||
public static bool Initialized2;
|
||||
public static bool Initialized;
|
||||
public static bool Terminated;
|
||||
public static IProfilingLogger ProfilingLogger;
|
||||
|
||||
@@ -200,7 +199,7 @@ namespace Umbraco.Tests.Runtimes
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
Ctored = Initialized1 = Initialized2 = Terminated = false;
|
||||
Ctored = Initialized = Terminated = false;
|
||||
ProfilingLogger = null;
|
||||
}
|
||||
|
||||
@@ -210,10 +209,19 @@ namespace Umbraco.Tests.Runtimes
|
||||
ProfilingLogger = proflog;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
Initialized = true;
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
Terminated = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Disposed = true;
|
||||
Terminated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,19 @@ namespace Umbraco.Web.Cache
|
||||
{
|
||||
public class DistributedCacheBinderComponent : IComponent
|
||||
{
|
||||
private readonly IDistributedCacheBinder _binder;
|
||||
|
||||
public DistributedCacheBinderComponent(IDistributedCacheBinder distributedCacheBinder)
|
||||
{
|
||||
distributedCacheBinder.BindEvents();
|
||||
_binder = distributedCacheBinder;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_binder.BindEvents();
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,17 +12,14 @@ namespace Umbraco.Web.Components
|
||||
private readonly IAuditService _auditService;
|
||||
private readonly IUserService _userService;
|
||||
|
||||
private IUser GetPerformingUser(int userId)
|
||||
{
|
||||
var found = userId >= 0 ? _userService.GetUserById(userId) : null;
|
||||
return found ?? new User {Id = 0, Name = "SYSTEM", Email = ""};
|
||||
}
|
||||
|
||||
public BackOfficeUserAuditEventsComponent(IAuditService auditService, IUserService userService)
|
||||
{
|
||||
_auditService = auditService;
|
||||
_userService = userService;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
//BackOfficeUserManager.AccountLocked += ;
|
||||
//BackOfficeUserManager.AccountUnlocked += ;
|
||||
BackOfficeUserManager.ForgotPasswordRequested += OnForgotPasswordRequest;
|
||||
@@ -34,7 +31,15 @@ namespace Umbraco.Web.Components
|
||||
BackOfficeUserManager.PasswordChanged += OnPasswordChanged;
|
||||
BackOfficeUserManager.PasswordReset += OnPasswordReset;
|
||||
//BackOfficeUserManager.ResetAccessFailedCount += ;
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
|
||||
private IUser GetPerformingUser(int userId)
|
||||
{
|
||||
var found = userId >= 0 ? _userService.GetUserById(userId) : null;
|
||||
return found ?? new User { Id = 0, Name = "SYSTEM", Email = "" };
|
||||
}
|
||||
|
||||
private static string FormatEmail(IMembershipUser user)
|
||||
@@ -42,7 +47,6 @@ namespace Umbraco.Web.Components
|
||||
return user == null ? string.Empty : user.Email.IsNullOrWhiteSpace() ? "" : $"<{user.Email}>";
|
||||
}
|
||||
|
||||
|
||||
private void OnLoginSuccess(object sender, EventArgs args)
|
||||
{
|
||||
if (args is IdentityAuditEventArgs identityArgs)
|
||||
|
||||
@@ -121,7 +121,10 @@ namespace Umbraco.Web.Components
|
||||
new BackgroundTaskRunnerOptions { AutoStart = true }, logger);
|
||||
_processTaskRunner = new BackgroundTaskRunner<IBackgroundTask>("ServerInstProcess",
|
||||
new BackgroundTaskRunnerOptions { AutoStart = true }, logger);
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
//We will start the whole process when a successful request is made
|
||||
UmbracoModule.RouteAttempt += RegisterBackgroundTasksOnce;
|
||||
|
||||
@@ -129,6 +132,9 @@ namespace Umbraco.Web.Components
|
||||
_messenger.Startup();
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Handle when a request is made
|
||||
/// </summary>
|
||||
|
||||
@@ -18,27 +18,39 @@ namespace Umbraco.Web.Components
|
||||
{
|
||||
public sealed class NotificationsComponent : IComponent
|
||||
{
|
||||
public NotificationsComponent(INotificationService notificationService, Notifier notifier, ActionCollection actions)
|
||||
private readonly Notifier _notifier;
|
||||
private readonly ActionCollection _actions;
|
||||
|
||||
public NotificationsComponent(Notifier notifier, ActionCollection actions)
|
||||
{
|
||||
_notifier = notifier;
|
||||
_actions = actions;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
//Send notifications for the send to publish action
|
||||
ContentService.SentToPublish += (sender, args) => notifier.Notify(actions.GetAction<ActionToPublish>(), args.Entity);
|
||||
ContentService.SentToPublish += (sender, args) => _notifier.Notify(_actions.GetAction<ActionToPublish>(), args.Entity);
|
||||
|
||||
//Send notifications for the published action
|
||||
ContentService.Published += (sender, args) => notifier.Notify(actions.GetAction<ActionPublish>(), args.PublishedEntities.ToArray());
|
||||
ContentService.Published += (sender, args) => _notifier.Notify(_actions.GetAction<ActionPublish>(), args.PublishedEntities.ToArray());
|
||||
|
||||
//Send notifications for the saved action
|
||||
ContentService.Sorted += (sender, args) => ContentServiceSorted(notifier, sender, args, actions);
|
||||
ContentService.Sorted += (sender, args) => ContentServiceSorted(_notifier, sender, args, _actions);
|
||||
|
||||
//Send notifications for the update and created actions
|
||||
ContentService.Saved += (sender, args) => ContentServiceSaved(notifier, sender, args, actions);
|
||||
ContentService.Saved += (sender, args) => ContentServiceSaved(_notifier, sender, args, _actions);
|
||||
|
||||
//Send notifications for the delete action
|
||||
ContentService.Deleted += (sender, args) => notifier.Notify(actions.GetAction<ActionDelete>(), args.DeletedEntities.ToArray());
|
||||
ContentService.Deleted += (sender, args) => _notifier.Notify(_actions.GetAction<ActionDelete>(), args.DeletedEntities.ToArray());
|
||||
|
||||
//Send notifications for the unpublish action
|
||||
ContentService.Unpublished += (sender, args) => notifier.Notify(actions.GetAction<ActionUnpublish>(), args.PublishedEntities.ToArray());
|
||||
ContentService.Unpublished += (sender, args) => _notifier.Notify(_actions.GetAction<ActionUnpublish>(), args.PublishedEntities.ToArray());
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
|
||||
private void ContentServiceSorted(Notifier notifier, IContentService sender, Core.Events.SaveEventArgs<IContent> args, ActionCollection actions)
|
||||
{
|
||||
var parentId = args.SavedEntities.Select(x => x.ParentId).Distinct().ToList();
|
||||
|
||||
@@ -8,11 +8,14 @@ namespace Umbraco.Web.Components
|
||||
{
|
||||
public sealed class PublicAccessComponent : IComponent
|
||||
{
|
||||
public PublicAccessComponent()
|
||||
public void Initialize()
|
||||
{
|
||||
MemberGroupService.Saved += MemberGroupService_Saved;
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
|
||||
static void MemberGroupService_Saved(IMemberGroupService sender, Core.Events.SaveEventArgs<Core.Models.IMemberGroup> e)
|
||||
{
|
||||
foreach (var grp in e.SavedEntities)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Web;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Components;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
@@ -9,30 +8,38 @@ namespace Umbraco.Web.Logging
|
||||
internal sealed class WebProfilerComponent : IComponent
|
||||
{
|
||||
private readonly WebProfiler _profiler;
|
||||
private readonly bool _profile;
|
||||
|
||||
public WebProfilerComponent(IProfiler profiler, ILogger logger, IRuntimeState runtime)
|
||||
public WebProfilerComponent(IProfiler profiler, ILogger logger)
|
||||
{
|
||||
_profile = true;
|
||||
|
||||
// although registered in WebRuntime.Compose, ensure that we have not
|
||||
// been replaced by another component, and we are still "the" profiler
|
||||
_profiler = profiler as WebProfiler;
|
||||
if (_profiler == null)
|
||||
{
|
||||
// if VoidProfiler was registered, let it be known
|
||||
var vp = profiler as VoidProfiler;
|
||||
if (vp != null)
|
||||
logger.Info<WebProfilerComponent>("Profiler is VoidProfiler, not profiling (must run debug mode to profile).");
|
||||
return;
|
||||
}
|
||||
if (_profiler != null) return;
|
||||
|
||||
// if VoidProfiler was registered, let it be known
|
||||
if (profiler is VoidProfiler)
|
||||
logger.Info<WebProfilerComponent>("Profiler is VoidProfiler, not profiling (must run debug mode to profile).");
|
||||
_profile = false;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
if (!_profile) return;
|
||||
|
||||
// bind to ApplicationInit - ie execute the application initialization for *each* application
|
||||
// it would be a mistake to try and bind to the current application events
|
||||
UmbracoApplicationBase.ApplicationInit += InitializeApplication;
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
|
||||
private void InitializeApplication(object sender, EventArgs args)
|
||||
{
|
||||
var app = sender as HttpApplication;
|
||||
if (app == null) return;
|
||||
if (!(sender is HttpApplication app)) return;
|
||||
|
||||
// for *each* application (this will run more than once)
|
||||
app.BeginRequest += (s, a) => _profiler.UmbracoApplicationBeginRequest(s, a);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Components;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
@@ -9,18 +8,26 @@ namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
internal sealed class PropertyEditorsComponent : IComponent
|
||||
{
|
||||
private readonly PropertyEditorCollection _propertyEditors;
|
||||
|
||||
public PropertyEditorsComponent(PropertyEditorCollection propertyEditors)
|
||||
{
|
||||
var fileUpload = propertyEditors.OfType<FileUploadPropertyEditor>().FirstOrDefault();
|
||||
_propertyEditors = propertyEditors;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
var fileUpload = _propertyEditors.OfType<FileUploadPropertyEditor>().FirstOrDefault();
|
||||
if (fileUpload != null) Initialize(fileUpload);
|
||||
|
||||
var imageCropper = propertyEditors.OfType<ImageCropperPropertyEditor>().FirstOrDefault();
|
||||
var imageCropper = _propertyEditors.OfType<ImageCropperPropertyEditor>().FirstOrDefault();
|
||||
if (imageCropper != null) Initialize(imageCropper);
|
||||
|
||||
// grid/examine moved to ExamineComponent
|
||||
}
|
||||
|
||||
// as long as these methods are private+static they won't be executed by the boot loader
|
||||
public void Terminate()
|
||||
{ }
|
||||
|
||||
private static void Initialize(FileUploadPropertyEditor fileUpload)
|
||||
{
|
||||
|
||||
@@ -8,5 +8,11 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
{
|
||||
// nothing - this just ensures that the service is created at boot time
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{ }
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,8 +69,7 @@ namespace Umbraco.Web.Redirects
|
||||
}
|
||||
}
|
||||
|
||||
public RedirectTrackingComponent()
|
||||
//protected void Initialize(ContentFinderCollectionBuilder contentFinderCollectionBuilder)
|
||||
public void Initialize()
|
||||
{
|
||||
// don't let the event handlers kick in if Redirect Tracking is turned off in the config
|
||||
if (UmbracoConfig.GetConfig<IUmbracoSettingsSection>("umbracoConfiguration/settings").WebRouting.DisableRedirectUrlTracking) return;
|
||||
@@ -103,6 +102,9 @@ namespace Umbraco.Web.Redirects
|
||||
// rolled back items have to be published, so publishing will take care of that
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
|
||||
private static void ContentCacheRefresher_CacheUpdated(ContentCacheRefresher sender,
|
||||
CacheRefresherEventArgs args)
|
||||
{
|
||||
|
||||
@@ -34,8 +34,17 @@ namespace Umbraco.Web.Runtime
|
||||
{
|
||||
public sealed class WebRuntimeComponent : IComponent
|
||||
{
|
||||
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
|
||||
private readonly SurfaceControllerTypeCollection _surfaceControllerTypes;
|
||||
private readonly UmbracoApiControllerTypeCollection _apiControllerTypes;
|
||||
private readonly IPublishedSnapshotService _publishedSnapshotService;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IUmbracoSettingsSection _umbracoSettings;
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
private readonly IVariationContextAccessor _variationContextAccessor;
|
||||
private readonly UrlProviderCollection _urlProviders;
|
||||
|
||||
public WebRuntimeComponent(
|
||||
IRuntimeState runtime,
|
||||
IUmbracoContextAccessor umbracoContextAccessor,
|
||||
SurfaceControllerTypeCollection surfaceControllerTypes,
|
||||
UmbracoApiControllerTypeCollection apiControllerTypes,
|
||||
@@ -43,15 +52,27 @@ namespace Umbraco.Web.Runtime
|
||||
IUserService userService,
|
||||
IUmbracoSettingsSection umbracoSettings,
|
||||
IGlobalSettings globalSettings,
|
||||
IEntityService entityService,
|
||||
IVariationContextAccessor variationContextAccessor,
|
||||
UrlProviderCollection urlProviders)
|
||||
{
|
||||
_umbracoContextAccessor = umbracoContextAccessor;
|
||||
_surfaceControllerTypes = surfaceControllerTypes;
|
||||
_apiControllerTypes = apiControllerTypes;
|
||||
_publishedSnapshotService = publishedSnapshotService;
|
||||
_userService = userService;
|
||||
_umbracoSettings = umbracoSettings;
|
||||
_globalSettings = globalSettings;
|
||||
_variationContextAccessor = variationContextAccessor;
|
||||
_urlProviders = urlProviders;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
// setup mvc and webapi services
|
||||
SetupMvcAndWebApi();
|
||||
|
||||
// client dependency
|
||||
ConfigureClientDependency(globalSettings);
|
||||
ConfigureClientDependency(_globalSettings);
|
||||
|
||||
// Disable the X-AspNetMvc-Version HTTP Header
|
||||
MvcHandler.DisableMvcResponseHeader = true;
|
||||
@@ -65,7 +86,7 @@ namespace Umbraco.Web.Runtime
|
||||
ConfigureGlobalFilters();
|
||||
|
||||
// set routes
|
||||
CreateRoutes(umbracoContextAccessor, globalSettings, surfaceControllerTypes, apiControllerTypes);
|
||||
CreateRoutes(_umbracoContextAccessor, _globalSettings, _surfaceControllerTypes, _apiControllerTypes);
|
||||
|
||||
// get an http context
|
||||
// at that moment, HttpContext.Current != null but its .Request property is null
|
||||
@@ -75,19 +96,22 @@ namespace Umbraco.Web.Runtime
|
||||
// (also sets the accessor)
|
||||
// this is a *temp* UmbracoContext
|
||||
UmbracoContext.EnsureContext(
|
||||
umbracoContextAccessor,
|
||||
_umbracoContextAccessor,
|
||||
new HttpContextWrapper(HttpContext.Current),
|
||||
publishedSnapshotService,
|
||||
new WebSecurity(httpContext, userService, globalSettings),
|
||||
umbracoSettings,
|
||||
urlProviders,
|
||||
globalSettings,
|
||||
variationContextAccessor);
|
||||
_publishedSnapshotService,
|
||||
new WebSecurity(httpContext, _userService, _globalSettings),
|
||||
_umbracoSettings,
|
||||
_urlProviders,
|
||||
_globalSettings,
|
||||
_variationContextAccessor);
|
||||
|
||||
// ensure WebAPI is initialized, after everything
|
||||
GlobalConfiguration.Configuration.EnsureInitialized();
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
|
||||
private static void ConfigureGlobalFilters()
|
||||
{
|
||||
GlobalFilters.Filters.Add(new EnsurePartialViewMacroViewContextFilterAttribute());
|
||||
|
||||
@@ -24,11 +24,11 @@ namespace Umbraco.Web.Scheduling
|
||||
private readonly HealthCheckCollection _healthChecks;
|
||||
private readonly HealthCheckNotificationMethodCollection _notifications;
|
||||
|
||||
private readonly BackgroundTaskRunner<IBackgroundTask> _keepAliveRunner;
|
||||
private readonly BackgroundTaskRunner<IBackgroundTask> _publishingRunner;
|
||||
private readonly BackgroundTaskRunner<IBackgroundTask> _tasksRunner;
|
||||
private readonly BackgroundTaskRunner<IBackgroundTask> _scrubberRunner;
|
||||
private readonly BackgroundTaskRunner<IBackgroundTask> _healthCheckRunner;
|
||||
private BackgroundTaskRunner<IBackgroundTask> _keepAliveRunner;
|
||||
private BackgroundTaskRunner<IBackgroundTask> _publishingRunner;
|
||||
private BackgroundTaskRunner<IBackgroundTask> _tasksRunner;
|
||||
private BackgroundTaskRunner<IBackgroundTask> _scrubberRunner;
|
||||
private BackgroundTaskRunner<IBackgroundTask> _healthCheckRunner;
|
||||
|
||||
private bool _started;
|
||||
private object _locker = new object();
|
||||
@@ -47,18 +47,26 @@ namespace Umbraco.Web.Scheduling
|
||||
|
||||
_healthChecks = healthChecks;
|
||||
_notifications = notifications;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
// backgrounds runners are web aware, if the app domain dies, these tasks will wind down correctly
|
||||
_keepAliveRunner = new BackgroundTaskRunner<IBackgroundTask>("KeepAlive", logger);
|
||||
_publishingRunner = new BackgroundTaskRunner<IBackgroundTask>("ScheduledPublishing", logger);
|
||||
_tasksRunner = new BackgroundTaskRunner<IBackgroundTask>("ScheduledTasks", logger);
|
||||
_scrubberRunner = new BackgroundTaskRunner<IBackgroundTask>("LogScrubber", logger);
|
||||
_healthCheckRunner = new BackgroundTaskRunner<IBackgroundTask>("HealthCheckNotifier", logger);
|
||||
_keepAliveRunner = new BackgroundTaskRunner<IBackgroundTask>("KeepAlive", _logger);
|
||||
_publishingRunner = new BackgroundTaskRunner<IBackgroundTask>("ScheduledPublishing", _logger);
|
||||
_tasksRunner = new BackgroundTaskRunner<IBackgroundTask>("ScheduledTasks", _logger);
|
||||
_scrubberRunner = new BackgroundTaskRunner<IBackgroundTask>("LogScrubber", _logger);
|
||||
_healthCheckRunner = new BackgroundTaskRunner<IBackgroundTask>("HealthCheckNotifier", _logger);
|
||||
|
||||
// we will start the whole process when a successful request is made
|
||||
UmbracoModule.RouteAttempt += RegisterBackgroundTasksOnce;
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
// the appdomain / maindom / whatever takes care of stopping background task runners
|
||||
}
|
||||
|
||||
private void RegisterBackgroundTasksOnce(object sender, RoutableAttemptEventArgs e)
|
||||
{
|
||||
switch (e.Outcome)
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Umbraco.Web.Search
|
||||
{
|
||||
private readonly IExamineManager _examineManager;
|
||||
private readonly IContentValueSetBuilder _contentValueSetBuilder;
|
||||
public IPublishedContentValueSetBuilder _publishedContentValueSetBuilder;
|
||||
private readonly IPublishedContentValueSetBuilder _publishedContentValueSetBuilder;
|
||||
private readonly IValueSetBuilder<IMedia> _mediaValueSetBuilder;
|
||||
private readonly IValueSetBuilder<IMember> _memberValueSetBuilder;
|
||||
private static bool _disableExamineIndexing = false;
|
||||
@@ -36,6 +36,10 @@ namespace Umbraco.Web.Search
|
||||
private readonly ServiceContext _services;
|
||||
private static BackgroundTaskRunner<IBackgroundTask> _rebuildOnStartupRunner;
|
||||
private static readonly object RebuildLocker = new object();
|
||||
private readonly IMainDom _mainDom;
|
||||
private readonly IProfilingLogger _logger;
|
||||
private readonly IUmbracoIndexesCreator _indexCreator;
|
||||
private readonly IndexRebuilder _indexRebuilder;
|
||||
|
||||
// the default enlist priority is 100
|
||||
// enlist with a lower priority to ensure that anything "default" runs after us
|
||||
@@ -59,6 +63,14 @@ namespace Umbraco.Web.Search
|
||||
_mediaValueSetBuilder = mediaValueSetBuilder;
|
||||
_memberValueSetBuilder = memberValueSetBuilder;
|
||||
|
||||
_mainDom = mainDom;
|
||||
_logger = profilingLogger;
|
||||
_indexCreator = indexCreator;
|
||||
_indexRebuilder = indexRebuilder;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
//we want to tell examine to use a different fs lock instead of the default NativeFSFileLock which could cause problems if the appdomain
|
||||
//terminates and in some rare cases would only allow unlocking of the file if IIS is forcefully terminated. Instead we'll rely on the simplefslock
|
||||
//which simply checks the existence of the lock file
|
||||
@@ -69,9 +81,9 @@ namespace Umbraco.Web.Search
|
||||
};
|
||||
|
||||
//let's deal with shutting down Examine with MainDom
|
||||
var examineShutdownRegistered = mainDom.Register(() =>
|
||||
var examineShutdownRegistered = _mainDom.Register(() =>
|
||||
{
|
||||
using (profilingLogger.TraceDuration<ExamineComponent>("Examine shutting down"))
|
||||
using (_logger.TraceDuration<ExamineComponent>("Examine shutting down"))
|
||||
{
|
||||
_examineManager.Dispose();
|
||||
}
|
||||
@@ -79,23 +91,23 @@ namespace Umbraco.Web.Search
|
||||
|
||||
if (!examineShutdownRegistered)
|
||||
{
|
||||
profilingLogger.Debug<ExamineComponent>("Examine shutdown not registered, this appdomain is not the MainDom, Examine will be disabled");
|
||||
_logger.Debug<ExamineComponent>("Examine shutdown not registered, this appdomain is not the MainDom, Examine will be disabled");
|
||||
|
||||
//if we could not register the shutdown examine ourselves, it means we are not maindom! in this case all of examine should be disabled!
|
||||
Suspendable.ExamineEvents.SuspendIndexers(profilingLogger);
|
||||
Suspendable.ExamineEvents.SuspendIndexers(_logger);
|
||||
_disableExamineIndexing = true;
|
||||
return; //exit, do not continue
|
||||
}
|
||||
|
||||
//create the indexes and register them with the manager
|
||||
foreach(var index in indexCreator.Create())
|
||||
foreach(var index in _indexCreator.Create())
|
||||
_examineManager.AddIndex(index);
|
||||
|
||||
profilingLogger.Debug<ExamineComponent>("Examine shutdown registered with MainDom");
|
||||
_logger.Debug<ExamineComponent>("Examine shutdown registered with MainDom");
|
||||
|
||||
var registeredIndexers = examineManager.Indexes.OfType<IUmbracoIndex>().Count(x => x.EnableDefaultEventHandler);
|
||||
var registeredIndexers = _examineManager.Indexes.OfType<IUmbracoIndex>().Count(x => x.EnableDefaultEventHandler);
|
||||
|
||||
profilingLogger.Info<ExamineComponent>("Adding examine event handlers for {RegisteredIndexers} index providers.", registeredIndexers);
|
||||
_logger.Info<ExamineComponent>("Adding examine event handlers for {RegisteredIndexers} index providers.", registeredIndexers);
|
||||
|
||||
// don't bind event handlers if we're not suppose to listen
|
||||
if (registeredIndexers == 0)
|
||||
@@ -108,12 +120,15 @@ namespace Umbraco.Web.Search
|
||||
MediaCacheRefresher.CacheUpdated += MediaCacheRefresherUpdated;
|
||||
MemberCacheRefresher.CacheUpdated += MemberCacheRefresherUpdated;
|
||||
|
||||
EnsureUnlocked(profilingLogger, examineManager);
|
||||
EnsureUnlocked(_logger, _examineManager);
|
||||
|
||||
//TODO: Instead of waiting 5000 ms, we could add an event handler on to fulfilling the first request, then start?
|
||||
RebuildIndexes(indexRebuilder, profilingLogger, true, 5000);
|
||||
RebuildIndexes(_indexRebuilder, _logger, true, 5000);
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Called to rebuild empty indexes on startup
|
||||
/// </summary>
|
||||
@@ -146,8 +161,6 @@ namespace Umbraco.Web.Search
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Must be called to each index is unlocked before any indexing occurs
|
||||
/// </summary>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Components;
|
||||
using Umbraco.Core.Sync;
|
||||
using Umbraco.Web.Cache;
|
||||
@@ -8,31 +9,39 @@ namespace Umbraco.Web.SignalR
|
||||
{
|
||||
public class PreviewHubComponent : IComponent
|
||||
{
|
||||
private readonly Lazy<IHubContext<IPreviewHub>> _hubContext;
|
||||
|
||||
// using a lazy arg here means that we won't create the hub until necessary
|
||||
// and therefore we won't have too bad an impact on boot time
|
||||
public PreviewHubComponent(Lazy<IHubContext<IPreviewHub>> hubContext)
|
||||
{
|
||||
// ContentService.Saved is too soon - the content cache is not ready yet
|
||||
// try using the content cache refresher event, because when it triggers
|
||||
// the cache has already been notified of the changes
|
||||
//ContentService.Saved += (sender, args) =>
|
||||
//{
|
||||
// var entity = args.SavedEntities.FirstOrDefault();
|
||||
// if (entity != null)
|
||||
// _previewHub.Clients.All.refreshed(entity.Id);
|
||||
//};
|
||||
_hubContext = hubContext;
|
||||
}
|
||||
|
||||
ContentCacheRefresher.CacheUpdated += (sender, args) =>
|
||||
public void Initialize()
|
||||
{
|
||||
// ContentService.Saved is too soon - the content cache is not ready yet,
|
||||
// so use the content cache refresher event, because when it triggers
|
||||
// the cache has already been notified of the changes
|
||||
|
||||
ContentCacheRefresher.CacheUpdated += HandleCacheUpdated;
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
ContentCacheRefresher.CacheUpdated -= HandleCacheUpdated;
|
||||
}
|
||||
|
||||
private void HandleCacheUpdated(ContentCacheRefresher sender, CacheRefresherEventArgs args)
|
||||
{
|
||||
if (args.MessageType != MessageType.RefreshByPayload) return;
|
||||
var payloads = (ContentCacheRefresher.JsonPayload[])args.MessageObject;
|
||||
var hubContextInstance = _hubContext.Value;
|
||||
foreach (var payload in payloads)
|
||||
{
|
||||
if (args.MessageType != MessageType.RefreshByPayload) return;
|
||||
var payloads = (ContentCacheRefresher.JsonPayload[])args.MessageObject;
|
||||
var hubContextInstance = hubContext.Value;
|
||||
foreach (var payload in payloads)
|
||||
{
|
||||
var id = payload.Id; // keep it simple for now, ignore ChangeTypes
|
||||
hubContextInstance.Clients.All.refreshed(id);
|
||||
}
|
||||
};
|
||||
var id = payload.Id; // keep it simple for now, ignore ChangeTypes
|
||||
hubContextInstance.Clients.All.refreshed(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user