From 33a773a0b93c82f82a4b5e49272d64be462e6504 Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 18 Oct 2016 17:09:26 +0200 Subject: [PATCH] Cleanup UmbracoContext --- .../PublishedContentCacheTests.cs | 2 +- src/Umbraco.Tests/LibraryTests.cs | 2 +- src/Umbraco.Tests/MockTests.cs | 4 +- .../PublishedContentDataTableTests.cs | 2 +- .../PublishedContentMoreTests.cs | 4 +- .../PublishedContentTestBase.cs | 2 +- .../Security/BackOfficeCookieManagerTests.cs | 4 +- .../TestHelpers/TestObjects-Mocks.cs | 8 +- .../TestHelpers/TestWithDatabaseBase.cs | 4 +- ...RenderIndexActionSelectorAttributeTests.cs | 13 +-- .../Web/Mvc/SurfaceControllerTests.cs | 11 +- .../Web/Mvc/UmbracoViewPageTests.cs | 2 +- .../Web/WebExtensionMethodTests.cs | 8 +- src/Umbraco.Web/Current.cs | 59 +++------- src/Umbraco.Web/UmbracoContext.cs | 101 +++++++----------- src/Umbraco.Web/UmbracoModule.cs | 14 ++- src/Umbraco.Web/WebRuntimeComponent.cs | 25 +++-- 17 files changed, 105 insertions(+), 160 deletions(-) diff --git a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs index 860d428583..b6af4eee19 100644 --- a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs +++ b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs @@ -69,7 +69,7 @@ namespace Umbraco.Tests.Cache.PublishedCache var facadeService = new Mock(); facadeService.Setup(x => x.CreateFacade(It.IsAny())).Returns(facade); - _umbracoContext = UmbracoContext.CreateContext( + _umbracoContext = new UmbracoContext( _httpContextFactory.HttpContext, facadeService.Object, new WebSecurity(_httpContextFactory.HttpContext, Current.Services.UserService), diff --git a/src/Umbraco.Tests/LibraryTests.cs b/src/Umbraco.Tests/LibraryTests.cs index 8d96e3cff4..e46b7fa830 100644 --- a/src/Umbraco.Tests/LibraryTests.cs +++ b/src/Umbraco.Tests/LibraryTests.cs @@ -48,7 +48,7 @@ namespace Umbraco.Tests .PropertyTypes.Count()); var umbracoContext = GetUmbracoContext("/test"); - Umbraco.Web.Current.SetUmbracoContext(umbracoContext, true); + Umbraco.Web.Current.UmbracoContextAccessor.UmbracoContext = umbracoContext; } /// diff --git a/src/Umbraco.Tests/MockTests.cs b/src/Umbraco.Tests/MockTests.cs index f4f5d0b69d..eb0aa67b5b 100644 --- a/src/Umbraco.Tests/MockTests.cs +++ b/src/Umbraco.Tests/MockTests.cs @@ -57,7 +57,7 @@ namespace Umbraco.Tests [Test] public void Can_Mock_Umbraco_Context() { - var umbracoContext = TestObjects.GetUmbracoContextMock(); + var umbracoContext = TestObjects.GetUmbracoContextMock(Current.UmbracoContextAccessor); Assert.AreEqual(umbracoContext, UmbracoContext.Current); } @@ -100,7 +100,7 @@ namespace Umbraco.Tests var urlProvider = urlProviderMock.Object; var theUrlProvider = new UrlProvider(umbracoContext, new [] { urlProvider }); - + Assert.AreEqual("/hello/world/1234", theUrlProvider.GetUrl(1234)); } } diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs index ac4d4a2586..1f3d6e3ba8 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs @@ -59,7 +59,7 @@ namespace Umbraco.Tests.PublishedContent var umbracoContext = GetUmbracoContext("/test"); //set the UmbracoContext.Current since the extension methods rely on it - Umbraco.Web.Current.SetUmbracoContext(umbracoContext, true); + Umbraco.Web.Current.UmbracoContextAccessor.UmbracoContext = umbracoContext; } public override void TearDown() diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs index 6d5d34ac2c..eff8551e48 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs @@ -64,14 +64,14 @@ namespace Umbraco.Tests.PublishedContent facadeService.Setup(x => x.CreateFacade(It.IsAny())).Returns(facade); var httpContext = GetHttpContextFactory("http://umbraco.local/", routeData).HttpContext; - var umbracoContext = UmbracoContext.CreateContext( + var umbracoContext = new UmbracoContext( httpContext, facadeService.Object, new WebSecurity(httpContext, Current.Services.UserService), TestObjects.GetUmbracoSettings(), Enumerable.Empty()); - Umbraco.Web.Current.SetUmbracoContext(umbracoContext, true); + Umbraco.Web.Current.UmbracoContextAccessor.UmbracoContext = umbracoContext; } public override void TearDown() diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs index fc7dc7a00d..5dd8fcee3d 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs @@ -27,7 +27,7 @@ namespace Umbraco.Tests.PublishedContent ContentTypesCache.GetPublishedContentTypeByAlias = (alias) => type; var umbracoContext = GetUmbracoContext("/test"); - Umbraco.Web.Current.SetUmbracoContext(umbracoContext, true); + Umbraco.Web.Current.UmbracoContextAccessor.UmbracoContext = umbracoContext; } protected override void MoreSetUp() diff --git a/src/Umbraco.Tests/Security/BackOfficeCookieManagerTests.cs b/src/Umbraco.Tests/Security/BackOfficeCookieManagerTests.cs index d70dec36cb..83c21b105a 100644 --- a/src/Umbraco.Tests/Security/BackOfficeCookieManagerTests.cs +++ b/src/Umbraco.Tests/Security/BackOfficeCookieManagerTests.cs @@ -25,7 +25,7 @@ namespace Umbraco.Tests.Security //should force app ctx to show not-configured ConfigurationManager.AppSettings.Set("umbracoConfigurationStatus", ""); - var umbracoContext = UmbracoContext.CreateContext( + var umbracoContext = new UmbracoContext( Mock.Of(), Mock.Of(), new WebSecurity(Mock.Of(), Current.Services.UserService), @@ -42,7 +42,7 @@ namespace Umbraco.Tests.Security [Test] public void ShouldAuthenticateRequest_When_Configured() { - var umbCtx = UmbracoContext.CreateContext( + var umbCtx = new UmbracoContext( Mock.Of(), Mock.Of(), new WebSecurity(Mock.Of(), Current.Services.UserService), diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs b/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs index f5aa36431c..2b6b150ef0 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs @@ -95,7 +95,7 @@ namespace Umbraco.Tests.TestHelpers /// /// An Umbraco context. /// This should be the minimum Umbraco context. - public static UmbracoContext GetUmbracoContextMock() + public static UmbracoContext GetUmbracoContextMock(IUmbracoContextAccessor accessor = null) { var httpContext = Mock.Of(); @@ -111,10 +111,8 @@ namespace Umbraco.Tests.TestHelpers var settings = GetUmbracoSettings(); var urlProviders = Enumerable.Empty(); - // fixme - // sort out Create vs New vs Ensure... - - return UmbracoContext.EnsureContext(httpContext, facadeService, webSecurity, settings, urlProviders, true); + if (accessor == null) accessor = new TestUmbracoContextAccessor(); + return UmbracoContext.EnsureContext(accessor, httpContext, facadeService, webSecurity, settings, urlProviders, true); } public static IUmbracoSettingsSection GetUmbracoSettings() diff --git a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs index 0f247d91f6..323c74ae60 100644 --- a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs +++ b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs @@ -434,7 +434,7 @@ namespace Umbraco.Tests.TestHelpers var httpContext = GetHttpContextFactory(url, routeData).HttpContext; - var umbracoContext = UmbracoContext.CreateContext( + var umbracoContext = new UmbracoContext( httpContext, service, new WebSecurity(httpContext, Core.DI.Current.Services.UserService), @@ -442,7 +442,7 @@ namespace Umbraco.Tests.TestHelpers urlProviders ?? Enumerable.Empty()); if (setSingleton) - Umbraco.Web.Current.SetUmbracoContext(umbracoContext, true); + Umbraco.Web.Current.UmbracoContextAccessor.UmbracoContext = umbracoContext; return umbracoContext; } diff --git a/src/Umbraco.Tests/Web/Mvc/RenderIndexActionSelectorAttributeTests.cs b/src/Umbraco.Tests/Web/Mvc/RenderIndexActionSelectorAttributeTests.cs index ada8200a3a..68c1aada49 100644 --- a/src/Umbraco.Tests/Web/Mvc/RenderIndexActionSelectorAttributeTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/RenderIndexActionSelectorAttributeTests.cs @@ -60,6 +60,7 @@ namespace Umbraco.Tests.Web.Mvc // CacheHelper.CreateDisabledCacheHelper(), // new ProfilingLogger(Mock.Of(), Mock.Of())); var umbCtx = UmbracoContext.EnsureContext( + Current.UmbracoContextAccessor, Mock.Of(), Mock.Of(), new Mock(null, null).Object, @@ -79,10 +80,8 @@ namespace Umbraco.Tests.Web.Mvc { var attr = new RenderIndexActionSelectorAttribute(); var req = new RequestContext(); - //var appCtx = new ApplicationContext( - // CacheHelper.CreateDisabledCacheHelper(), - // new ProfilingLogger(Mock.Of(), Mock.Of())); var umbCtx = UmbracoContext.EnsureContext( + Current.UmbracoContextAccessor, Mock.Of(), Mock.Of(), new Mock(null, null).Object, @@ -102,10 +101,8 @@ namespace Umbraco.Tests.Web.Mvc { var attr = new RenderIndexActionSelectorAttribute(); var req = new RequestContext(); - //var appCtx = new ApplicationContext( - // CacheHelper.CreateDisabledCacheHelper(), - // new ProfilingLogger(Mock.Of(), Mock.Of())); var umbCtx = UmbracoContext.EnsureContext( + Current.UmbracoContextAccessor, Mock.Of(), Mock.Of(), new Mock(null, null).Object, @@ -125,10 +122,8 @@ namespace Umbraco.Tests.Web.Mvc { var attr = new RenderIndexActionSelectorAttribute(); var req = new RequestContext(); - //var appCtx = new ApplicationContext( - // CacheHelper.CreateDisabledCacheHelper(), - // new ProfilingLogger(Mock.Of(), Mock.Of())); var umbCtx = UmbracoContext.EnsureContext( + Current.UmbracoContextAccessor, Mock.Of(), Mock.Of(), new Mock(null, null).Object, diff --git a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs index 8eedadea4c..e614d8d285 100644 --- a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs @@ -33,6 +33,7 @@ namespace Umbraco.Tests.Web.Mvc public void Can_Construct_And_Get_Result() { var umbracoContext = UmbracoContext.EnsureContext( + Current.UmbracoContextAccessor, new Mock().Object, Mock.Of(), new Mock(null, null).Object, @@ -50,13 +51,8 @@ namespace Umbraco.Tests.Web.Mvc [Test] public void Umbraco_Context_Not_Null() { - //var appCtx = new ApplicationContext( - // CacheHelper.CreateDisabledCacheHelper(), - // new ProfilingLogger(Mock.Of(), Mock.Of())); - - //Current.ApplicationContext = appCtx; // FIXME horrible - var umbCtx = UmbracoContext.EnsureContext( + Current.UmbracoContextAccessor, new Mock().Object, Mock.Of(), new Mock(null, null).Object, @@ -73,6 +69,7 @@ namespace Umbraco.Tests.Web.Mvc public void Umbraco_Helper_Not_Null() { var umbracoContext = UmbracoContext.EnsureContext( + Current.UmbracoContextAccessor, new Mock().Object, Mock.Of(), new Mock(null, null).Object, @@ -96,6 +93,7 @@ namespace Umbraco.Tests.Web.Mvc facadeService.Setup(x => x.CreateFacade(It.IsAny())).Returns(facade.Object); var umbracoContext = UmbracoContext.EnsureContext( + Current.UmbracoContextAccessor, new Mock().Object, facadeService.Object, new Mock(null, null).Object, @@ -130,6 +128,7 @@ namespace Umbraco.Tests.Web.Mvc var webRoutingSettings = Mock.Of(section => section.UrlProviderMode == "AutoLegacy"); var umbracoContext = UmbracoContext.EnsureContext( + Current.UmbracoContextAccessor, new Mock().Object, Mock.Of(), new Mock(null, null).Object, diff --git a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs index 0bc9626015..676ec9cf80 100644 --- a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs @@ -420,7 +420,7 @@ namespace Umbraco.Tests.Web.Mvc var http = GetHttpContextFactory(url, routeData).HttpContext; - var ctx = UmbracoContext.CreateContext( + var ctx = new UmbracoContext( GetHttpContextFactory(url, routeData).HttpContext, _service, new WebSecurity(http, Current.Services.UserService), diff --git a/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs b/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs index 090a823946..4f2256d15b 100644 --- a/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs +++ b/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs @@ -22,7 +22,7 @@ namespace Umbraco.Tests.Web [Test] public void RouteDataExtensions_GetUmbracoContext() { - var umbCtx = UmbracoContext.CreateContext( + var umbCtx = new UmbracoContext( Mock.Of(), Mock.Of(), new WebSecurity(Mock.Of(), Current.Services.UserService), @@ -38,7 +38,7 @@ namespace Umbraco.Tests.Web [Test] public void ControllerContextExtensions_GetUmbracoContext_From_RouteValues() { - var umbCtx = UmbracoContext.CreateContext( + var umbCtx = new UmbracoContext( Mock.Of(), Mock.Of(), new WebSecurity(Mock.Of(), Current.Services.UserService), @@ -64,7 +64,7 @@ namespace Umbraco.Tests.Web [Test] public void ControllerContextExtensions_GetUmbracoContext_From_Current() { - var umbCtx = UmbracoContext.CreateContext( + var umbCtx = new UmbracoContext( Mock.Of(), Mock.Of(), new WebSecurity(Mock.Of(), Current.Services.UserService), @@ -83,7 +83,7 @@ namespace Umbraco.Tests.Web var ctx3 = CreateViewContext(new ControllerContext(httpContext, r3, new MyController())); Current.UmbracoContextAccessor = new TestUmbracoContextAccessor(); - Current.SetUmbracoContext(umbCtx, true); + Current.UmbracoContextAccessor.UmbracoContext = umbCtx; var result = ctx3.GetUmbracoContext(); diff --git a/src/Umbraco.Web/Current.cs b/src/Umbraco.Web/Current.cs index d5ee7776e8..43084bbe59 100644 --- a/src/Umbraco.Web/Current.cs +++ b/src/Umbraco.Web/Current.cs @@ -35,7 +35,6 @@ namespace Umbraco.Web private static readonly object Locker = new object(); private static IUmbracoContextAccessor _umbracoContextAccessor; - private static IFacadeAccessor _facadeAccessor; static Current() { @@ -44,7 +43,6 @@ namespace Umbraco.Web if (_umbracoContextAccessor != null) ClearUmbracoContext(); _umbracoContextAccessor = null; - _facadeAccessor = null; }; } @@ -57,37 +55,10 @@ namespace Umbraco.Web private static ServiceContainer Container => CoreCurrent.Container; - // Facade - // - // is managed by the FacadeAccessor - // - // have to support setting the accessor directly (vs container) for tests - // fixme - not sure about this - should tests use a container? - - public static IFacadeAccessor FacadeAccessor - { - get - { - if (_facadeAccessor != null) return _facadeAccessor; - return _facadeAccessor = Container.GetInstance(); - } - set { _facadeAccessor = value; } // for tests - } - - // UmbracoContext - // - // is managed by the UmbracoContext Acceesor - // - // have to support setting the accessor directly (vs container) for tests - // fixme - note sure about this - should tests use a container? - // - // have to support setting it for now, because of 'ensure umbraco context' which can create - // contexts pretty much at any time and in an uncontrolled way - and when we do not have - // proper access to the accessor. - // - // have to support clear, because of the weird mixed accessor we're using that can - // store things in thread-static var that need to be cleared, else it retains rogue values. + #region Temp & Special + // fixme - have to keep this until tests are refactored + // but then, it should all be managed properly in the container public static IUmbracoContextAccessor UmbracoContextAccessor { get @@ -98,20 +69,9 @@ namespace Umbraco.Web set { _umbracoContextAccessor = value; } // for tests } - public static UmbracoContext UmbracoContext - => UmbracoContextAccessor.UmbracoContext; - - public static void SetUmbracoContext(UmbracoContext value, bool canReplace) - { - lock (Locker) - { - if (UmbracoContextAccessor.UmbracoContext != null && canReplace == false) - throw new InvalidOperationException("Current UmbracoContext can be set only once per request."); - UmbracoContextAccessor.UmbracoContext?.Dispose(); // dispose the one that is being replaced, if any - UmbracoContextAccessor.UmbracoContext = value; - } - } - + // clears the "current" umbraco context + // at the moment the "current" umbraco context can end up being disposed and should get cleared + // in the accessor - this should be done differently but for the time being we have to support it public static void ClearUmbracoContext() { lock (Locker) @@ -121,10 +81,15 @@ namespace Umbraco.Web } } + #endregion + #region Web Getters + public static UmbracoContext UmbracoContext + => UmbracoContextAccessor.UmbracoContext; + public static IFacade Facade - => FacadeAccessor.Facade; + => Container.GetInstance().Facade; public static EventMessages EventMessages => Container.GetInstance().GetOrDefault(); diff --git a/src/Umbraco.Web/UmbracoContext.cs b/src/Umbraco.Web/UmbracoContext.cs index e9f94a6608..441a0443a9 100644 --- a/src/Umbraco.Web/UmbracoContext.cs +++ b/src/Umbraco.Web/UmbracoContext.cs @@ -22,26 +22,27 @@ namespace Umbraco.Web #region Ensure Context /// - /// This is a helper method which is called to ensure that the singleton context is created + /// Ensures that there is a "current" UmbracoContext. /// - /// - /// - /// - /// - /// - /// - /// if set to true will replace the current singleton with a new one, this is generally only ever used because - /// during application startup the base url domain will not be available so after app startup we'll replace the current - /// context with a new one in which we can access the httpcontext.Request object. - /// - /// - /// The Singleton context object - /// + /// An http context. + /// A facade service. + /// A security helper. + /// The umbraco settings. + /// Some url providers. + /// A value indicating whether to replace the existing context. + /// The "current" UmbracoContext. /// - /// This is created in order to standardize the creation of the singleton. Normally it is created during a request - /// in the UmbracoModule, however this module does not execute during application startup so we need to ensure it - /// during the startup process as well. - /// See: http://issues.umbraco.org/issue/U4-1890, http://issues.umbraco.org/issue/U4-1717 + /// fixme - this needs to be clarified + /// + /// If is true then the "current" UmbracoContext is replaced + /// with a new one even if there is one already. See . Has to do with + /// creating a context at startup and not being able to access httpContext.Request at that time, so + /// the OriginalRequestUrl remains unspecified until replaces the context. + /// + /// This *has* to be done differently! + /// + /// See http://issues.umbraco.org/issue/U4-1890, http://issues.umbraco.org/issue/U4-1717 + /// /// // used by // UmbracoModule BeginRequest (since it's a request it has an UmbracoContext) @@ -55,64 +56,48 @@ namespace Umbraco.Web // and tests // can .ContentRequest be null? of course! public static UmbracoContext EnsureContext( + IUmbracoContextAccessor umbracoContextAccessor, HttpContextBase httpContext, IFacadeService facadeService, WebSecurity webSecurity, IUmbracoSettingsSection umbracoSettings, IEnumerable urlProviders, - bool replaceContext) + bool replace = false) { + if (umbracoContextAccessor == null) throw new ArgumentNullException(nameof(umbracoContextAccessor)); if (httpContext == null) throw new ArgumentNullException(nameof(httpContext)); + if (facadeService == null) throw new ArgumentNullException(nameof(facadeService)); if (webSecurity == null) throw new ArgumentNullException(nameof(webSecurity)); if (umbracoSettings == null) throw new ArgumentNullException(nameof(umbracoSettings)); if (urlProviders == null) throw new ArgumentNullException(nameof(urlProviders)); // if there is already a current context, return if not replacing - var umbracoContext = Web.Current.UmbracoContext; - if (umbracoContext != null && replaceContext == false) - return umbracoContext; + var current = umbracoContextAccessor.UmbracoContext; + if (current != null && replace == false) + return current; - // create, assign the singleton, and return - umbracoContext = CreateContext(httpContext, facadeService, webSecurity, umbracoSettings, urlProviders); - // fixme... ?! - Web.Current.SetUmbracoContext(umbracoContext, replaceContext); // will dispose the one that is being replaced - return umbracoContext; + // create & assign to accessor, dispose existing if any + umbracoContextAccessor.UmbracoContext?.Dispose(); + return umbracoContextAccessor.UmbracoContext = new UmbracoContext(httpContext, facadeService, webSecurity, umbracoSettings, urlProviders); } - /// - /// Creates a standalone UmbracoContext instance - /// - /// - /// - /// - /// - /// - /// - /// A new instance of UmbracoContext - /// - // internal for tests - internal static UmbracoContext CreateContext( - HttpContextBase httpContext, - IFacadeService facadeService, - WebSecurity webSecurity, - IUmbracoSettingsSection umbracoSettings, - IEnumerable urlProviders) - { - if (httpContext == null) throw new ArgumentNullException(nameof(httpContext)); - if (webSecurity == null) throw new ArgumentNullException(nameof(webSecurity)); - if (umbracoSettings == null) throw new ArgumentNullException(nameof(umbracoSettings)); - if (urlProviders == null) throw new ArgumentNullException(nameof(urlProviders)); - - return new UmbracoContext(httpContext, facadeService, webSecurity, umbracoSettings, urlProviders); - } - - private UmbracoContext( + // initializes a new instance of the UmbracoContext class + // internal for unit tests + // otherwise it's used by EnsureContext above + // warn: does *not* manage setting any IUmbracoContextAccessor + internal UmbracoContext( HttpContextBase httpContext, IFacadeService facadeService, WebSecurity webSecurity, IUmbracoSettingsSection umbracoSettings, IEnumerable urlProviders) { + if (httpContext == null) throw new ArgumentNullException(nameof(httpContext)); + if (facadeService == null) throw new ArgumentNullException(nameof(facadeService)); + if (webSecurity == null) throw new ArgumentNullException(nameof(webSecurity)); + if (umbracoSettings == null) throw new ArgumentNullException(nameof(umbracoSettings)); + if (urlProviders == null) throw new ArgumentNullException(nameof(urlProviders)); + // ensure that this instance is disposed when the request terminates, though we *also* ensure // this happens in the Umbraco module since the UmbracoCOntext is added to the HttpContext items. // @@ -123,11 +108,8 @@ namespace Umbraco.Web // it is ok and it will be actually disposed only once. httpContext.DisposeOnPipelineCompleted(this); - if (httpContext == null) throw new ArgumentNullException(nameof(httpContext)); - ObjectCreated = DateTime.Now; UmbracoRequestId = Guid.NewGuid(); - HttpContext = httpContext; Security = webSecurity; @@ -143,7 +125,6 @@ namespace Umbraco.Web // OriginalRequestUrl = GetRequestFromContext()?.Url ?? new Uri("http://localhost"); CleanedUmbracoUrl = UriUtility.UriToUmbraco(OriginalRequestUrl); - UrlProvider = new UrlProvider(this, umbracoSettings.WebRouting, urlProviders); } @@ -327,7 +308,7 @@ namespace Umbraco.Web // reset - important when running outside of http context // also takes care of the accessor - Web.Current.SetUmbracoContext(null, true); + Web.Current.ClearUmbracoContext(); // help caches release resources // (but don't create caches just to dispose them) diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs index 0c66cf69a4..737790a0fd 100644 --- a/src/Umbraco.Web/UmbracoModule.cs +++ b/src/Umbraco.Web/UmbracoModule.cs @@ -33,6 +33,9 @@ namespace Umbraco.Web // get our dependencies injected manually, through properties, in // Init(). works for dependencies that are singletons. + [Inject] + public IUmbracoContextAccessor UmbracoContextAccessor { get; set; } + [Inject] public IFacadeService FacadeService { get; set; } @@ -67,16 +70,16 @@ namespace Umbraco.Web private void BeginRequest(HttpContextBase httpContext) { // ensure application url is initialized - ((RuntimeState)Current.RuntimeState).EnsureApplicationUrl(httpContext.Request); + ((RuntimeState) Current.RuntimeState).EnsureApplicationUrl(httpContext.Request); // do not process if client-side request if (httpContext.Request.Url.IsClientSideRequest()) return; - //write the trace output for diagnostics at the end of the request + // write the trace output for diagnostics at the end of the request httpContext.Trace.Write("UmbracoModule", "Umbraco request begins"); - // ok, process + // process // create the LegacyRequestInitializer // and initialize legacy stuff @@ -84,9 +87,10 @@ namespace Umbraco.Web legacyRequestInitializer.InitializeRequest(); // create the UmbracoContext singleton, one per request, and assign - // NOTE: we assign 'true' to ensure the context is replaced if it is already set (i.e. during app startup) + // replace existing if any (eg during app startup, a temp one is created) UmbracoContext.EnsureContext( - httpContext, + UmbracoContextAccessor, + httpContext, FacadeService, new WebSecurity(httpContext, UserService), UmbracoConfig.For.UmbracoSettings(), diff --git a/src/Umbraco.Web/WebRuntimeComponent.cs b/src/Umbraco.Web/WebRuntimeComponent.cs index 16c31e9094..92d1697eb7 100644 --- a/src/Umbraco.Web/WebRuntimeComponent.cs +++ b/src/Umbraco.Web/WebRuntimeComponent.cs @@ -179,7 +179,10 @@ namespace Umbraco.Web IRuntimeState runtime, IUmbracoContextAccessor umbracoContextAccessor, SurfaceControllerTypeCollection surfaceControllerTypes, - UmbracoApiControllerTypeCollection apiControllerTypes) + UmbracoApiControllerTypeCollection apiControllerTypes, + IFacadeService facadeService, + IUserService userService, + UrlProviderCollection urlProviders) { // setup mvc and webapi services SetupMvcAndWebApi(); @@ -218,19 +221,19 @@ namespace Umbraco.Web CreateRoutes(umbracoContextAccessor, surfaceControllerTypes, apiControllerTypes); // get an http context - // fixme - although HttpContext.Current is NOT null during Application_Start - // it does NOT have a request and therefore no request ... + // at that moment, HttpContext.Current != null but its .Request property is null var httpContext = new HttpContextWrapper(HttpContext.Current); - //before we do anything, we'll ensure the umbraco context - //see: http://issues.umbraco.org/issue/U4-1717 - UmbracoContext.EnsureContext( // fixme - refactor! UmbracoContext & UmbracoRequestContext! + inject, accessor, etc - httpContext, - Current.FacadeService, // fixme inject! stop using current here! - new WebSecurity(httpContext, Current.Services.UserService),// fixme inject! stop using current here! + // ensure there is an UmbracoContext + // (also sets the accessor) + // this is a *temp* UmbracoContext + UmbracoContext.EnsureContext( + umbracoContextAccessor, + new HttpContextWrapper(HttpContext.Current), + facadeService, + new WebSecurity(httpContext, userService), UmbracoConfig.For.UmbracoSettings(), - Current.UrlProviders,// fixme inject! stop using current here! - false); + urlProviders); // rebuild any empty indexes // do we want to make this optional? otherwise the only way to disable this on startup