diff --git a/src/Umbraco.Core/ApplicationContext.cs b/src/Umbraco.Core/ApplicationContext.cs index 503b7e7dd0..0e497531f1 100644 --- a/src/Umbraco.Core/ApplicationContext.cs +++ b/src/Umbraco.Core/ApplicationContext.cs @@ -44,32 +44,6 @@ namespace Umbraco.Core Init(); } - /// - /// Constructor - /// - /// - /// - /// - [Obsolete("Use the other constructor specifying a ProfilingLogger instead")] - public ApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext, CacheHelper cache) - : this(dbContext, serviceContext, cache, - new ProfilingLogger(LoggerResolver.Current.Logger, ProfilerResolver.Current.Profiler)) - { - } - - /// - /// Creates a basic app context - /// - /// - [Obsolete("Use the other constructor specifying a ProfilingLogger instead")] - public ApplicationContext(CacheHelper cache) - { - if (cache == null) throw new ArgumentNullException("cache"); - ApplicationCache = cache; - ProfilingLogger = new ProfilingLogger(LoggerResolver.Current.Logger, ProfilerResolver.Current.Profiler); - Init(); - } - /// /// Creates a basic app context /// @@ -106,33 +80,6 @@ namespace Umbraco.Core return Current; } - /// - /// A method used to create and ensure that a global ApplicationContext singleton is created. - /// - /// - /// - /// If set to true will replace the current singleton instance - This should only be used for unit tests or on app - /// startup if for some reason the boot manager is not the umbraco boot manager. - /// - /// - /// - /// - /// - /// This is NOT thread safe - /// - [Obsolete("Use the other method specifying an ProfilingLogger instead")] - public static ApplicationContext EnsureContext(DatabaseContext dbContext, ServiceContext serviceContext, CacheHelper cache, bool replaceContext) - { - if (Current != null) - { - if (!replaceContext) - return Current; - } - var ctx = new ApplicationContext(dbContext, serviceContext, cache); - Current = ctx; - return Current; - } - /// /// A method used to create and ensure that a global ApplicationContext singleton is created. /// diff --git a/src/Umbraco.Core/CoreBootManager.cs b/src/Umbraco.Core/CoreBootManager.cs index c56b02d74e..5a56e8e846 100644 --- a/src/Umbraco.Core/CoreBootManager.cs +++ b/src/Umbraco.Core/CoreBootManager.cs @@ -48,7 +48,7 @@ namespace Umbraco.Core protected ProfilingLogger ProfilingLogger { get; private set; } private DisposableTimer _timer; protected PluginManager PluginManager { get; private set; } - private CacheHelper _cacheHelper; + private bool _isInitialized = false; private bool _isStarted = false; @@ -88,16 +88,28 @@ namespace Umbraco.Core if (_isInitialized) throw new InvalidOperationException("The boot manager has already been initialized"); + //Create logger/profiler, and their resolvers, these are special resolvers that can be resolved before frozen so we can start logging + LoggerResolver.Current = new LoggerResolver(_umbracoApplication.Logger) { CanResolveBeforeFrozen = true }; + var profiler = CreateProfiler(); + ProfilerResolver.Current = new ProfilerResolver(profiler) { CanResolveBeforeFrozen = true }; + ProfilingLogger = new ProfilingLogger(_umbracoApplication.Logger, profiler); + ProfilingLogger = ProfilingLogger?? new ProfilingLogger(LoggerResolver.Current.Logger, ProfilerResolver.Current.Profiler); + + ApplicationCache = CreateApplicationCache(); _timer = ProfilingLogger.TraceDuration( string.Format("Umbraco {0} application starting on {1}", UmbracoVersion.GetSemanticVersion().ToSemanticString(), NetworkHelper.MachineName), "Umbraco application startup complete"); - _cacheHelper = CreateApplicationCache(); - ServiceProvider = new ActivatorServiceProvider(); - PluginManager.Current = PluginManager = new PluginManager(ServiceProvider, _cacheHelper.RuntimeCache, ProfilingLogger, true); - ApplicationCache = CreateApplicationCache(); + ServiceProvider = new ActivatorServiceProvider(); + + //create the plugin manager + //TODO: this is currently a singleton but it would be better if it weren't. Unfortunately the only way to get + // rid of this singleton would be to put it into IoC and then use the ServiceLocator pattern. + PluginManager.Current = PluginManager = new PluginManager(ServiceProvider, ApplicationCache.RuntimeCache, ProfilingLogger, true); + + //build up core IoC servoces ConfigureCoreServices(Container); //set the singleton resolved from the core container @@ -117,14 +129,24 @@ namespace Umbraco.Core _appStartupEvtContainer.RegisterCollection(PluginManager.ResolveApplicationStartupHandlers()); //build up standard IoC services - ConfigureServices(Container); + ConfigureApplicationServices(Container); InitializeResolvers(); InitializeModelMappers(); //now we need to call the initialize methods - //TODO: Make sure to try/catch the OnApplicationInitialized!! - Parallel.ForEach(_appStartupEvtContainer.GetAllInstances(), x => x.OnApplicationInitialized(UmbracoApplication, ApplicationContext)); + Parallel.ForEach(_appStartupEvtContainer.GetAllInstances(), x => + { + try + { + x.OnApplicationInitialized(UmbracoApplication, ApplicationContext); + } + catch (Exception ex) + { + ProfilingLogger.Logger.Error("An error occurred running OnApplicationInitialized for handler " + x.GetType(), ex); + throw; + } + }); _isInitialized = true; @@ -134,20 +156,19 @@ namespace Umbraco.Core /// /// Build the core container which contains all core things requird to build an app context /// - private void ConfigureCoreServices(ServiceContainer container) + internal virtual void ConfigureCoreServices(ServiceContainer container) { container.Register(factory => container); container.Register(factory => _umbracoApplication.Logger, new PerContainerLifetime()); container.Register(factory => ProfilingLogger.Profiler, new PerContainerLifetime()); container.Register(factory => ProfilingLogger, new PerContainerLifetime()); - var settings = UmbracoConfig.For.UmbracoSettings(); - container.Register(factory => settings); - container.Register(factory => settings.Content); - container.Register(factory => settings.RequestHandler); + container.Register(factory => UmbracoConfig.For.UmbracoSettings()); + container.Register(factory => factory.GetInstance().Content); + container.Register(factory => factory.GetInstance().RequestHandler); //TODO: Add the other config areas... - container.Register(factory => _cacheHelper, new PerContainerLifetime()); - container.Register(factory => _cacheHelper.RuntimeCache, new PerContainerLifetime()); + container.Register(factory => ApplicationCache, new PerContainerLifetime()); + container.Register(factory => ApplicationCache.RuntimeCache, new PerContainerLifetime()); container.Register(); container.Register(factory => PluginManager, new PerContainerLifetime()); container.Register(factory => new DefaultDatabaseFactory(GlobalSettings.UmbracoConnectionName, factory.GetInstance())); @@ -185,7 +206,7 @@ namespace Umbraco.Core /// Called to customize the IoC container /// /// - internal virtual void ConfigureServices(ServiceContainer container) + internal virtual void ConfigureApplicationServices(ServiceContainer container) { } @@ -270,9 +291,19 @@ namespace Umbraco.Core if (_isStarted) throw new InvalidOperationException("The boot manager has already been initialized"); - //TODO: Make sure to try/catch the OnApplicationInitialized!! //call OnApplicationStarting of each application events handler - Parallel.ForEach(_appStartupEvtContainer.GetAllInstances(), x => x.OnApplicationStarting(UmbracoApplication, ApplicationContext)); + Parallel.ForEach(_appStartupEvtContainer.GetAllInstances(), x => + { + try + { + x.OnApplicationStarting(UmbracoApplication, ApplicationContext); + } + catch (Exception ex) + { + ProfilingLogger.Logger.Error("An error occurred running OnApplicationStarting for handler " + x.GetType(), ex); + throw; + } + }); if (afterStartup != null) { @@ -307,9 +338,18 @@ namespace Umbraco.Core //call OnApplicationStarting of each application events handler - //TODO: Make sure to try/catch the OnApplicationInitialized!! - Parallel.ForEach(_appStartupEvtContainer.GetAllInstances(), x => x.OnApplicationStarted(UmbracoApplication, ApplicationContext)); - + Parallel.ForEach(_appStartupEvtContainer.GetAllInstances(), x => + { + try + { + x.OnApplicationStarted(UmbracoApplication, ApplicationContext); + } + catch (Exception ex) + { + ProfilingLogger.Logger.Error("An error occurred running OnApplicationStarted for handler " + x.GetType(), ex); + throw; + } + }); //end the current scope which was created to intantiate all of the startup handlers _appStartupEvtContainer.EndCurrentScope(); @@ -372,8 +412,9 @@ namespace Umbraco.Core /// protected virtual void InitializeResolvers() { - var manifestParser = new ManifestParser(ProfilingLogger.Logger, new DirectoryInfo(IOHelper.MapPath("~/App_Plugins")), _cacheHelper.RuntimeCache); - var manifestBuilder = new ManifestBuilder(_cacheHelper.RuntimeCache, manifestParser); + + var manifestParser = new ManifestParser(ProfilingLogger.Logger, new DirectoryInfo(IOHelper.MapPath("~/App_Plugins")), ApplicationCache.RuntimeCache); + var manifestBuilder = new ManifestBuilder(ApplicationCache.RuntimeCache, manifestParser); PropertyEditorResolver.Current = new PropertyEditorResolver( Container, ProfilingLogger.Logger, () => PluginManager.ResolvePropertyEditors(), diff --git a/src/Umbraco.Tests/BootManagers/CoreBootManagerTests.cs b/src/Umbraco.Tests/BootManagers/CoreBootManagerTests.cs index 12e5f8de6a..847560af71 100644 --- a/src/Umbraco.Tests/BootManagers/CoreBootManagerTests.cs +++ b/src/Umbraco.Tests/BootManagers/CoreBootManagerTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Web; +using LightInject; using Moq; using NUnit.Framework; using Umbraco.Core; @@ -12,6 +13,7 @@ using Umbraco.Core.ObjectResolution; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Tests.TestHelpers; using umbraco.interfaces; +using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Persistence; using Umbraco.Core.Profiling; using Umbraco.Core.Services; @@ -21,23 +23,12 @@ namespace Umbraco.Tests.BootManagers [TestFixture] public class CoreBootManagerTests : BaseUmbracoConfigurationTest { - - private TestApp _testApp; - - [SetUp] - public override void Initialize() - { - base.Initialize(); - _testApp = new TestApp(); - } - [TearDown] public override void TearDown() { base.TearDown(); - - _testApp = null; ResolverCollection.ResetAll(); + TestApplicationEventHandler.Reset(); } @@ -50,6 +41,16 @@ namespace Umbraco.Tests.BootManagers { return new TestBootManager(this, new ProfilingLogger(Mock.Of(), Mock.Of())); } + + private ILogger _logger; + + /// + /// Returns the logger instance for the application - this will be used throughout the entire app + /// + public override ILogger Logger + { + get { return _logger ?? (_logger = Mock.Of()); } + } } /// @@ -61,16 +62,35 @@ namespace Umbraco.Tests.BootManagers : base(umbracoApplication, logger) { } + + internal override void ConfigureCoreServices(ServiceContainer container) + { + base.ConfigureCoreServices(container); + container.Register(factory => SettingsForTests.GetDefault()); + container.Register(factory => new DatabaseContext( + factory.GetInstance(), + factory.GetInstance(), + factory.GetInstance()), new PerContainerLifetime()); + } } /// /// test event handler /// - public class TestApplicationEventHandler : IApplicationEventHandler + public class TestApplicationEventHandler : DisposableObject, IApplicationEventHandler { + public static void Reset() + { + Initialized = false; + Starting = false; + Started = false; + Disposed = false; + } + public static bool Initialized = false; public static bool Starting = false; public static bool Started = false; + public static bool Disposed = false; public void OnApplicationInitialized(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext) { @@ -86,20 +106,39 @@ namespace Umbraco.Tests.BootManagers { Started = true; } + + protected override void DisposeResources() + { + Disposed = true; + } + } + + [Test] + public void Disposes_App_Startup_Handlers_After_Startup() + { + using (var app = new TestApp()) + { + app.StartApplication(app, new EventArgs()); + + Assert.IsTrue(TestApplicationEventHandler.Disposed); + } } [Test] public void Handle_IApplicationEventHandler_Objects_Outside_Web_Context() { - _testApp.StartApplication(_testApp, new EventArgs()); + using (var app = new TestApp()) + { + app.StartApplication(app, new EventArgs()); - Assert.IsTrue(TestApplicationEventHandler.Initialized); - Assert.IsTrue(TestApplicationEventHandler.Starting); - Assert.IsTrue(TestApplicationEventHandler.Started); + Assert.IsTrue(TestApplicationEventHandler.Initialized); + Assert.IsTrue(TestApplicationEventHandler.Starting); + Assert.IsTrue(TestApplicationEventHandler.Started); + } } [Test] - public void Raises_Events() + public void Raises_Starting_Events() { using (var app = new TestApp()) { @@ -119,13 +158,11 @@ namespace Umbraco.Tests.BootManagers app.ApplicationStarting += starting; app.ApplicationStarted += started; - _testApp.StartApplication(_testApp, new EventArgs()); + app.StartApplication(app, new EventArgs()); app.ApplicationStarting -= starting; app.ApplicationStarting -= started; } - - } } diff --git a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs index ae939778cb..3d408b1222 100644 --- a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs +++ b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs @@ -21,27 +21,6 @@ namespace Umbraco.Tests.Cache.PublishedCache private ContextualPublishedContentCache _cache; private XmlDocument _xml; - private string GetLegacyXml() - { - return @" - -]> - - - - - - - - - - - - -"; - } - private string GetXml() { return @"(), () => PluginManager.Current.ResolveAssignedMapperTypes())); - } - } - protected virtual ISqlSyntaxProvider SqlSyntax { get { return new SqlCeSyntaxProvider(); } @@ -118,12 +108,12 @@ namespace Umbraco.Tests.TestHelpers new DatabaseContext(dbFactory, Logger, SqlSyntax, "System.Data.SqlServerCe.4.0"), //assign the service context new ServiceContext( - repositoryFactory, - new PetaPocoUnitOfWorkProvider(dbFactory), - new FileUnitOfWorkProvider(), - new PublishingStrategy(evtMsgs, Logger), - cacheHelper, - Logger, + repositoryFactory, + new PetaPocoUnitOfWorkProvider(dbFactory), + new FileUnitOfWorkProvider(), + new PublishingStrategy(evtMsgs, Logger), + cacheHelper, + Logger, evtMsgs, Enumerable.Empty()), cacheHelper, @@ -132,7 +122,7 @@ namespace Umbraco.Tests.TestHelpers IsReady = true }; - base.Initialize(); + ApplicationContext.Current = _appContext; using (ProfilingLogger.TraceDuration("init")) { @@ -143,8 +133,8 @@ namespace Umbraco.Tests.TestHelpers InitializeDatabase(); //ensure the configuration matches the current version for tests - SettingsForTests.ConfigurationStatus = UmbracoVersion.GetSemanticVersion().ToSemanticString(); - } + SettingsForTests.ConfigurationStatus = UmbracoVersion.Current.ToString(3); + } } /// diff --git a/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs b/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs index 4fae7a0564..c1a2f2b930 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs @@ -109,6 +109,16 @@ namespace Umbraco.Tests.TestHelpers private static readonly object Locker = new object(); + private MappingResolver _mappingResolver; + protected IMappingResolver MappingResolver + { + get + { + return _mappingResolver ?? + (_mappingResolver = new MappingResolver(Container, Mock.Of(), () => PluginManager.Current.ResolveAssignedMapperTypes())); + } + } + private static void InitializeLegacyMappingsForCoreEditors() { lock (Locker) @@ -181,7 +191,7 @@ namespace Umbraco.Tests.TestHelpers { var sqlSyntax = new SqlCeSyntaxProvider(); - var repoFactory = new RepositoryFactory(CacheHelper.CreateDisabledCacheHelper(), Logger, sqlSyntax, SettingsForTests.GenerateMockSettings(), Mock.Of()); + var repoFactory = new RepositoryFactory(CacheHelper.CreateDisabledCacheHelper(), Logger, sqlSyntax, SettingsForTests.GenerateMockSettings(), MappingResolver); var evtMsgs = new TransientMessagesFactory(); ApplicationContext.Current = new ApplicationContext( diff --git a/src/Umbraco.Web/WebBootManager.cs b/src/Umbraco.Web/WebBootManager.cs index d1c5177652..3d2dbcfb7e 100644 --- a/src/Umbraco.Web/WebBootManager.cs +++ b/src/Umbraco.Web/WebBootManager.cs @@ -308,16 +308,24 @@ namespace Umbraco.Web } /// - /// Called to customize the IoC container + /// Build the core container which contains all core things requird to build an app context /// - /// - internal override void ConfigureServices(ServiceContainer container) + internal override void ConfigureCoreServices(ServiceContainer container) { - base.ConfigureServices(container); + base.ConfigureCoreServices(container); //Replace services: container.Register(); + } + /// + /// Called to customize the IoC container + /// + /// + internal override void ConfigureApplicationServices(ServiceContainer container) + { + base.ConfigureApplicationServices(container); + //IoC setup for LightInject for mvc/webapi Container.EnableMvc(); Container.RegisterMvcControllers(PluginManager);