diff --git a/src/Umbraco.Core/Events/UmbracoApplicationStarting.cs b/src/Umbraco.Core/Events/UmbracoApplicationStarting.cs index 422673a823..e78a6e4608 100644 --- a/src/Umbraco.Core/Events/UmbracoApplicationStarting.cs +++ b/src/Umbraco.Core/Events/UmbracoApplicationStarting.cs @@ -1,5 +1,9 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + namespace Umbraco.Core.Events { + public class UmbracoApplicationStarting : INotification { /// diff --git a/src/Umbraco.Core/Events/UmbracoRequestBegin.cs b/src/Umbraco.Core/Events/UmbracoRequestBegin.cs new file mode 100644 index 0000000000..c72ddc904d --- /dev/null +++ b/src/Umbraco.Core/Events/UmbracoRequestBegin.cs @@ -0,0 +1,23 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Umbraco.Web; + +namespace Umbraco.Core.Events +{ + /// + /// Notification raised on each request begin. + /// + public class UmbracoRequestBegin : INotification + { + /// + /// Initializes a new instance of the class. + /// + public UmbracoRequestBegin(IUmbracoContext umbracoContext) => UmbracoContext = umbracoContext; + + /// + /// Gets the + /// + public IUmbracoContext UmbracoContext { get; } + } +} diff --git a/src/Umbraco.Web.Common/Events/UmbracoRequestEnd.cs b/src/Umbraco.Core/Events/UmbracoRequestEnd.cs similarity index 60% rename from src/Umbraco.Web.Common/Events/UmbracoRequestEnd.cs rename to src/Umbraco.Core/Events/UmbracoRequestEnd.cs index 459eca2bba..1988a2dd50 100644 --- a/src/Umbraco.Web.Common/Events/UmbracoRequestEnd.cs +++ b/src/Umbraco.Core/Events/UmbracoRequestEnd.cs @@ -1,7 +1,7 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. -using Microsoft.AspNetCore.Http; +using Umbraco.Web; namespace Umbraco.Core.Events { @@ -13,11 +13,11 @@ namespace Umbraco.Core.Events /// /// Initializes a new instance of the class. /// - public UmbracoRequestEnd(HttpContext httpContext) => HttpContext = httpContext; + public UmbracoRequestEnd(IUmbracoContext umbracoContext) => UmbracoContext = umbracoContext; /// - /// Gets the + /// Gets the /// - public HttpContext HttpContext { get; } + public IUmbracoContext UmbracoContext { get; } } } diff --git a/src/Umbraco.Core/Routing/EnsureRoutableOutcome.cs b/src/Umbraco.Core/Routing/EnsureRoutableOutcome.cs deleted file mode 100644 index 0c6ac7c564..0000000000 --- a/src/Umbraco.Core/Routing/EnsureRoutableOutcome.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace Umbraco.Web.Routing -{ - /// - /// Represents the outcome of trying to route an incoming request. - /// - public enum EnsureRoutableOutcome - { - /// - /// Request routes to a document. - /// - /// - /// Umbraco was ready and configured, and has content. - /// The request looks like it can be a route to a document. This does not - /// mean that there *is* a matching document, ie the request might end up returning - /// 404. - /// - IsRoutable = 0, - - /// - /// Request does not route to a document. - /// - /// - /// Umbraco was ready and configured, and has content. - /// The request does not look like it can be a route to a document. Can be - /// anything else eg back-office, surface controller... - /// - NotDocumentRequest = 10, - - /// - /// Umbraco was not ready. - /// - NotReady = 11, - - /// - /// There was no content at all. - /// - NoContent = 12 - } -} diff --git a/src/Umbraco.Core/Routing/RoutableAttemptEventArgs.cs b/src/Umbraco.Core/Routing/RoutableAttemptEventArgs.cs deleted file mode 100644 index 9f80d8ed3f..0000000000 --- a/src/Umbraco.Core/Routing/RoutableAttemptEventArgs.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Umbraco.Web.Routing -{ - /// - /// Event args containing information about why the request was not routable, or if it is routable - /// - public class RoutableAttemptEventArgs : UmbracoRequestEventArgs - { - public EnsureRoutableOutcome Outcome { get; private set; } - - public RoutableAttemptEventArgs(EnsureRoutableOutcome reason, IUmbracoContext umbracoContext) - : base(umbracoContext) - { - Outcome = reason; - } - } -} diff --git a/src/Umbraco.Core/Routing/UmbracoRequestEventArgs.cs b/src/Umbraco.Core/Routing/UmbracoRequestEventArgs.cs deleted file mode 100644 index d93a27ddf4..0000000000 --- a/src/Umbraco.Core/Routing/UmbracoRequestEventArgs.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace Umbraco.Web.Routing -{ - /// - /// Event args used for event launched during a request (like in the UmbracoModule) - /// - public class UmbracoRequestEventArgs : EventArgs - { - public IUmbracoContext UmbracoContext { get; private set; } - - public UmbracoRequestEventArgs(IUmbracoContext umbracoContext) - { - UmbracoContext = umbracoContext; - } - } -} diff --git a/src/Umbraco.Core/Web/IRequestAccessor.cs b/src/Umbraco.Core/Web/IRequestAccessor.cs index 85ab5cff97..275c96bf23 100644 --- a/src/Umbraco.Core/Web/IRequestAccessor.cs +++ b/src/Umbraco.Core/Web/IRequestAccessor.cs @@ -5,13 +5,22 @@ namespace Umbraco.Web { public interface IRequestAccessor { + /// + /// Returns the request/form/querystring value for the given name + /// string GetRequestValue(string name); + + /// + /// Returns the query string value for the given name + /// string GetQueryStringValue(string name); - event EventHandler EndRequest; - event EventHandler RouteAttempt; + + /// + /// Returns the current request uri + /// Uri GetRequestUrl(); - // TODO: Not sure this belongs here but we can leave it for now + // TODO: This doesn't belongs here Uri GetApplicationUrl(); } } diff --git a/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs b/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs index 1ad2b44740..fc3f66c28f 100644 --- a/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs +++ b/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs @@ -11,10 +11,9 @@ namespace Umbraco.Infrastructure.Cache /// /// Ensures that distributed cache events are setup and the is initialized /// - public sealed class DatabaseServerMessengerNotificationHandler : INotificationHandler + public sealed class DatabaseServerMessengerNotificationHandler : INotificationHandler, INotificationHandler { private readonly IServerMessenger _messenger; - private readonly IRequestAccessor _requestAccessor; private readonly IUmbracoDatabaseFactory _databaseFactory; private readonly IDistributedCacheBinder _distributedCacheBinder; private readonly ILogger _logger; @@ -24,12 +23,10 @@ namespace Umbraco.Infrastructure.Cache /// public DatabaseServerMessengerNotificationHandler( IServerMessenger serverMessenger, - IRequestAccessor requestAccessor, IUmbracoDatabaseFactory databaseFactory, IDistributedCacheBinder distributedCacheBinder, ILogger logger) { - _requestAccessor = requestAccessor; _databaseFactory = databaseFactory; _distributedCacheBinder = distributedCacheBinder; _logger = logger; @@ -38,19 +35,6 @@ namespace Umbraco.Infrastructure.Cache /// public void Handle(UmbracoApplicationStarting notification) - { - // The scheduled tasks - TouchServerTask and InstructionProcessTask - run as .NET Core hosted services. - // The former (as well as other hosted services that run outside of an HTTP request context) depends on the application URL - // being available (via IRequestAccessor), which can only be retrieved within an HTTP request (unless it's explicitly configured). - // Hence we hook up a one-off task on an HTTP request to ensure this is retrieved, which caches the value and makes it available - // for the hosted services to use when the HTTP request is not available. - _requestAccessor.RouteAttempt += EnsureApplicationUrlOnce; - _requestAccessor.EndRequest += EndRequest; - - Startup(); - } - - private void Startup() { if (_databaseFactory.CanConnect == false) { @@ -65,28 +49,9 @@ namespace Umbraco.Infrastructure.Cache } } - // TODO: I don't really know or think that the Application Url plays a role anymore with the DB dist cache, - // this might be really old stuff. I 'think' all this is doing is ensuring that the IRequestAccessor.GetApplicationUrl - // is definitely called during the first request. If that is still required, that logic doesn't belong here. That logic - // should be part of it's own service/middleware. There's also TODO notes within IRequestAccessor.GetApplicationUrl directly - // mentioning that the property doesn't belong on that service either. This should be investigated and resolved in a separate task. - private void EnsureApplicationUrlOnce(object sender, RoutableAttemptEventArgs e) - { - if (e.Outcome == EnsureRoutableOutcome.IsRoutable || e.Outcome == EnsureRoutableOutcome.NotDocumentRequest) - { - _requestAccessor.RouteAttempt -= EnsureApplicationUrlOnce; - EnsureApplicationUrl(); - } - } - - // By retrieving the application URL within the context of a request (as we are here in responding - // to the IRequestAccessor's RouteAttempt event), we'll get it from the HTTP context and save it for - // future requests that may not be within an HTTP request (e.g. from hosted services). - private void EnsureApplicationUrl() => _requestAccessor.GetApplicationUrl(); - /// /// Clear the batch on end request /// - private void EndRequest(object sender, UmbracoRequestEventArgs e) => _messenger?.SendMessages(); + public void Handle(UmbracoRequestEnd notification) => _messenger?.SendMessages(); } } diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs index b88c2346a7..e816972989 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs @@ -38,6 +38,7 @@ namespace Umbraco.Infrastructure.DependencyInjection builder.SetDatabaseServerMessengerCallbacks(GetCallbacks); builder.SetServerMessenger(); builder.AddNotificationHandler(); + builder.AddNotificationHandler(); return builder; } diff --git a/src/Umbraco.ModelsBuilder.Embedded/LiveModelsProvider.cs b/src/Umbraco.ModelsBuilder.Embedded/LiveModelsProvider.cs index cf5235387d..eafc006c26 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/LiveModelsProvider.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/LiveModelsProvider.cs @@ -117,7 +117,7 @@ namespace Umbraco.ModelsBuilder.Embedded public void Handle(UmbracoRequestEnd notification) { - if (IsEnabled && _mainDom.IsMainDom && !notification.HttpContext.Request.IsClientSideRequest()) + if (IsEnabled && _mainDom.IsMainDom) { GenerateModelsIfRequested(); } diff --git a/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs b/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs deleted file mode 100644 index 2ec0113c2f..0000000000 --- a/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs +++ /dev/null @@ -1,124 +0,0 @@ -using System; -using System.Threading; -using Microsoft.Extensions.Logging; -using Moq; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Configuration.Models; -using Umbraco.Tests.Common.Builders; -using Umbraco.Tests.TestHelpers; -using Umbraco.Web; - -namespace Umbraco.Tests.Routing -{ - [TestFixture] - [Apartment(ApartmentState.STA)] - public class UmbracoModuleTests : BaseWebTest - { - private UmbracoInjectedModule _module; - - public override void SetUp() - { - base.SetUp(); - - // FIXME: be able to get the UmbracoModule from the container. any reason settings were from testobjects? - //create the module - var logger = Mock.Of(); - - var globalSettings = new GlobalSettings { ReservedPaths = GlobalSettings.StaticReservedPaths + "~/umbraco" }; - var runtime = Umbraco.Core.RuntimeState.Booting(); - - _module = new UmbracoInjectedModule - ( - runtime, - logger, - Mock.Of(), - globalSettings, - HostingEnvironment - ); - - runtime.Level = RuntimeLevel.Run; - - - //SettingsForTests.ReservedPaths = "~/umbraco,~/install/"; - //SettingsForTests.ReservedUrls = "~/config/splashes/booting.aspx,~/install/default.aspx,~/config/splashes/noNodes.aspx,~/VSEnterpriseHelper.axd"; - - } - - public override void TearDown() - { - base.TearDown(); - - _module.DisposeIfDisposable(); - } - - // do not test for /base here as it's handled before EnsureUmbracoRoutablePage is called - [TestCase("/umbraco_client/Tree/treeIcons.css", false)] - [TestCase("/umbraco_client/Tree/Themes/umbraco/style.css?cdv=37", false)] - [TestCase("/umbraco/editContent.aspx", false)] - [TestCase("/install/default.aspx", false)] - [TestCase("/install/?installStep=license", false)] - [TestCase("/install?installStep=license", false)] - [TestCase("/install/test.aspx", false)] - [TestCase("/config/splashes/noNodes.aspx", false)] - [TestCase("/", true)] - [TestCase("/home.aspx", true)] - [TestCase("/umbraco-test", true)] - [TestCase("/install-test", true)] - public void Ensure_Request_Routable(string url, bool assert) - { - var httpContextFactory = new FakeHttpContextFactory(url); - var httpContext = httpContextFactory.HttpContext; - var umbracoContext = GetUmbracoContext(url); - - var result = _module.EnsureUmbracoRoutablePage(umbracoContext, httpContext); - - Assert.AreEqual(assert, result.Success); - } - - //NOTE: This test shows how we can test most of the HttpModule, it however is testing a method that no longer exists and is testing too much, - // we need to write unit tests for each of the components: NiceUrlProvider, all of the Lookup classes, etc... - // to ensure that each one is individually tested. - - //[TestCase("/", 1046)] - //[TestCase("/home.aspx", 1046)] - //[TestCase("/home/sub1.aspx", 1173)] - //[TestCase("/home.aspx?altTemplate=blah", 1046)] - //public void Process_Front_End_Document_Request_Match_Node(string url, int nodeId) - //{ - // var httpContextFactory = new FakeHttpContextFactory(url); - // var httpContext = httpContextFactory.HttpContext; - // var umbracoContext = new UmbracoContext(httpContext, ApplicationContext.Current, new NullRoutesCache()); - // var contentStore = new ContentStore(umbracoContext); - // var niceUrls = new NiceUrlProvider(contentStore, umbracoContext); - // umbracoContext.RoutingContext = new RoutingContext( - // new IPublishedContentLookup[] {new LookupByNiceUrl()}, - // new DefaultLastChanceLookup(), - // contentStore, - // niceUrls); - - // StateHelper.HttpContext = httpContext; - - // //because of so much dependency on the db, we need to create som stuff here, i originally abstracted out stuff but - // //was turning out to be quite a deep hole because ultimately we'd have to abstract the old 'Domain' and 'Language' classes - // Domain.MakeNew("Test.com", 1000, Language.GetByCultureCode("en-US").id); - - // //need to create a template with id 1045 - // var template = Template.MakeNew("test", new User(0)); - - // SetupUmbracoContextForTest(umbracoContext, template); - - // _module.AssignDocumentRequest(httpContext, umbracoContext, httpContext.Request.Url); - - // Assert.IsNotNull(umbracoContext.PublishedContentRequest); - // Assert.IsNotNull(umbracoContext.PublishedContentRequest.XmlNode); - // Assert.IsFalse(umbracoContext.PublishedContentRequest.IsRedirect); - // Assert.IsFalse(umbracoContext.PublishedContentRequest.Is404); - // Assert.AreEqual(umbracoContext.PublishedContentRequest.Culture, Thread.CurrentThread.CurrentCulture); - // Assert.AreEqual(umbracoContext.PublishedContentRequest.Culture, Thread.CurrentThread.CurrentUICulture); - // Assert.AreEqual(nodeId, umbracoContext.PublishedContentRequest.NodeId); - - //} - - } -} diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index 78f9fc3013..c306451f66 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -226,7 +226,6 @@ namespace Umbraco.Tests.Testing services.AddUnique(ipResolver); services.AddUnique(); services.AddUnique(TestHelper.ShortStringHelper); - services.AddUnique(); services.AddUnique(); diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index b09787dd2c..f614ac6130 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -243,7 +243,6 @@ - diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs index c88612c2c7..7e1dbb3c9c 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.Extensions.Options; @@ -10,42 +11,45 @@ using Umbraco.Web.Routing; namespace Umbraco.Web.Common.AspNetCore { - public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler, INotificationHandler + public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler { private readonly IHttpContextAccessor _httpContextAccessor; - private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly WebRoutingSettings _webRoutingSettings; private readonly ISet _applicationUrls = new HashSet(); private Uri _currentApplicationUrl; + private object _initLocker = new object(); + private bool _hasAppUrl = false; + private bool _isInit = false; - public AspNetCoreRequestAccessor(IHttpContextAccessor httpContextAccessor, - IUmbracoContextAccessor umbracoContextAccessor, + /// + /// Initializes a new instance of the class. + /// + public AspNetCoreRequestAccessor( + IHttpContextAccessor httpContextAccessor, IOptions webRoutingSettings) { _httpContextAccessor = httpContextAccessor; - _umbracoContextAccessor = umbracoContextAccessor; _webRoutingSettings = webRoutingSettings.Value; } - + /// public string GetRequestValue(string name) => GetFormValue(name) ?? GetQueryStringValue(name); - public string GetFormValue(string name) + private string GetFormValue(string name) { var request = _httpContextAccessor.GetRequiredHttpContext().Request; if (!request.HasFormContentType) return null; return request.Form[name]; } + /// public string GetQueryStringValue(string name) => _httpContextAccessor.GetRequiredHttpContext().Request.Query[name]; - public event EventHandler EndRequest; - - public event EventHandler RouteAttempt; - + /// public Uri GetRequestUrl() => _httpContextAccessor.HttpContext != null ? new Uri(_httpContextAccessor.HttpContext.Request.GetEncodedUrl()) : null; + /// public Uri GetApplicationUrl() { // Fixme: This causes problems with site swap on azure because azure pre-warms a site by calling into `localhost` and when it does that @@ -80,17 +84,16 @@ namespace Umbraco.Web.Common.AspNetCore return _currentApplicationUrl; } + /// + /// This just initializes the application URL on first request attempt + /// TODO: This doesn't belong here, the GetApplicationUrl doesn't belong to IRequestAccessor + /// this should be part of middleware not a lazy init based on an INotification + /// public void Handle(UmbracoRequestBegin notification) - { - var reason = EnsureRoutableOutcome.IsRoutable; //TODO get the correct value here like in UmbracoInjectedModule - RouteAttempt?.Invoke(this, new RoutableAttemptEventArgs(reason, _umbracoContextAccessor.UmbracoContext)); - } - - public void Handle(UmbracoRequestEnd notification) - { - EndRequest?.Invoke(this, new UmbracoRequestEventArgs(_umbracoContextAccessor.UmbracoContext)); - } - - + => LazyInitializer.EnsureInitialized(ref _hasAppUrl, ref _isInit, ref _initLocker, () => + { + GetApplicationUrl(); + return true; + }); } } diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs index 4b9953edf7..2dfb98d6e2 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs @@ -233,7 +233,6 @@ namespace Umbraco.Web.Common.DependencyInjection builder.Services.AddUnique(); builder.Services.AddUnique(); builder.AddNotificationHandler(); - builder.AddNotificationHandler(); // Password hasher builder.Services.AddUnique(); diff --git a/src/Umbraco.Web.Common/Events/UmbracoRequestBegin.cs b/src/Umbraco.Web.Common/Events/UmbracoRequestBegin.cs deleted file mode 100644 index 82d9edacbc..0000000000 --- a/src/Umbraco.Web.Common/Events/UmbracoRequestBegin.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using Microsoft.AspNetCore.Http; - -namespace Umbraco.Core.Events -{ - /// - /// Notification raised on each request begin. - /// - public class UmbracoRequestBegin : INotification - { - public UmbracoRequestBegin(HttpContext httpContext) - { - HttpContext = httpContext; - } - - public HttpContext HttpContext { get; } - }; -} diff --git a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs index 069c38d3c5..cee2d0e6e7 100644 --- a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs +++ b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs @@ -95,7 +95,7 @@ namespace Umbraco.Web.Common.Middleware try { - await _eventAggregator.PublishAsync(new UmbracoRequestBegin(context)); + await _eventAggregator.PublishAsync(new UmbracoRequestBegin(umbracoContextReference.UmbracoContext)); } catch (Exception ex) { @@ -111,7 +111,7 @@ namespace Umbraco.Web.Common.Middleware } finally { - await _eventAggregator.PublishAsync(new UmbracoRequestEnd(context)); + await _eventAggregator.PublishAsync(new UmbracoRequestEnd(umbracoContextReference.UmbracoContext)); } } } @@ -119,7 +119,7 @@ namespace Umbraco.Web.Common.Middleware { if (isFrontEndRequest) { - LogHttpRequest.TryGetCurrentHttpRequestId(out var httpRequestId, _requestCache); + LogHttpRequest.TryGetCurrentHttpRequestId(out Guid httpRequestId, _requestCache); _logger.LogTrace("End Request [{HttpRequestId}]: {RequestUrl} ({RequestDuration}ms)", httpRequestId, pathAndQuery, DateTime.Now.Subtract(umbracoContextReference.UmbracoContext.ObjectCreated).TotalMilliseconds); } diff --git a/src/Umbraco.Web/AspNet/AspNetRequestAccessor.cs b/src/Umbraco.Web/AspNet/AspNetRequestAccessor.cs deleted file mode 100644 index ae38dc2c05..0000000000 --- a/src/Umbraco.Web/AspNet/AspNetRequestAccessor.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.Extensions.Options; -using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Web.Routing; - -namespace Umbraco.Web.AspNet -{ - public class AspNetRequestAccessor : IRequestAccessor - { - private readonly IHttpContextAccessor _httpContextAccessor; - private readonly WebRoutingSettings _webRoutingSettings; - private readonly ISet _applicationUrls = new HashSet(); - private Uri _currentApplicationUrl; - public AspNetRequestAccessor(IHttpContextAccessor httpContextAccessor, IOptions webRoutingSettings) - { - _httpContextAccessor = httpContextAccessor; - _webRoutingSettings = webRoutingSettings.Value; - - UmbracoModule.EndRequest += OnEndRequest; - UmbracoModule.RouteAttempt += OnRouteAttempt; - } - - - - public string GetRequestValue(string name) - { - return _httpContextAccessor.GetRequiredHttpContext().Request[name]; - } - - public string GetQueryStringValue(string name) - { - return _httpContextAccessor.GetRequiredHttpContext().Request.QueryString[name]; - } - - private void OnEndRequest(object sender, UmbracoRequestEventArgs args) - { - EndRequest?.Invoke(sender, args); - } - - private void OnRouteAttempt(object sender, RoutableAttemptEventArgs args) - { - RouteAttempt?.Invoke(sender, args); - } - public event EventHandler EndRequest; - public event EventHandler RouteAttempt; - public Uri GetRequestUrl() => _httpContextAccessor.HttpContext?.Request.Url; - public Uri GetApplicationUrl() - { - //Fixme: This causes problems with site swap on azure because azure pre-warms a site by calling into `localhost` and when it does that - // it changes the URL to `localhost:80` which actually doesn't work for pinging itself, it only works internally in Azure. The ironic part - // about this is that this is here specifically for the slot swap scenario https://issues.umbraco.org/issue/U4-10626 - - - // see U4-10626 - in some cases we want to reset the application url - // (this is a simplified version of what was in 7.x) - // note: should this be optional? is it expensive? - - if (!(_webRoutingSettings.UmbracoApplicationUrl is null)) - { - return new Uri(_webRoutingSettings.UmbracoApplicationUrl); - } - - var request = _httpContextAccessor.HttpContext?.Request; - - var url = request?.Url.GetLeftPart(UriPartial.Authority); - var change = url != null && !_applicationUrls.Contains(url); - if (change) - { - _applicationUrls.Add(url); - - _currentApplicationUrl ??= new Uri(url); - } - - return _currentApplicationUrl; - } - } -} diff --git a/src/Umbraco.Web/Runtime/WebInitialComposer.cs b/src/Umbraco.Web/Runtime/WebInitialComposer.cs index d4e989854f..3f166c5747 100644 --- a/src/Umbraco.Web/Runtime/WebInitialComposer.cs +++ b/src/Umbraco.Web/Runtime/WebInitialComposer.cs @@ -21,9 +21,6 @@ namespace Umbraco.Web.Runtime { base.Compose(builder); - builder.Services.AddTransient(); - - // register membership stuff builder.Services.AddTransient(factory => MembershipProviderExtensions.GetMembersMembershipProvider()); builder.Services.AddTransient(factory => Roles.Enabled ? Roles.Provider : new MembersRoleProvider(factory.GetRequiredService())); diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index f5445a4bc9..2113175e51 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -131,7 +131,6 @@ - @@ -177,7 +176,6 @@ - @@ -245,7 +243,6 @@ Code - Component diff --git a/src/Umbraco.Web/UmbracoInjectedModule.cs b/src/Umbraco.Web/UmbracoInjectedModule.cs deleted file mode 100644 index b50f4ce23e..0000000000 --- a/src/Umbraco.Web/UmbracoInjectedModule.cs +++ /dev/null @@ -1,243 +0,0 @@ -using System; -using System.Web; -using System.Web.Routing; -using Microsoft.Extensions.Logging; -using Umbraco.Core; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Exceptions; -using Umbraco.Core.Hosting; -using Umbraco.Core.Security; -using Umbraco.Web.Composing; -using Umbraco.Web.Routing; - -namespace Umbraco.Web -{ - // notes - // - // also look at IOHelper.ResolveUrlsFromTextString - nightmarish?! - // - // context.RewritePath supports ~/ or else must begin with /vdir - // Request.RawUrl is still there - // response.Redirect does?! always remap to /vdir?! - - /// - /// Represents the main Umbraco module. - /// - /// - /// Is registered by the . - /// Do *not* try to use that one as a module in web.config. - /// - public class UmbracoInjectedModule : IHttpModule - { - private readonly IRuntimeState _runtime; - private readonly ILogger _logger; - private readonly IUmbracoContextFactory _umbracoContextFactory; - private readonly GlobalSettings _globalSettings; - private readonly IHostingEnvironment _hostingEnvironment; - - public UmbracoInjectedModule( - IRuntimeState runtime, - ILogger logger, - IUmbracoContextFactory umbracoContextFactory, - GlobalSettings globalSettings, - IHostingEnvironment hostingEnvironment) - { - _runtime = runtime; - _logger = logger; - _umbracoContextFactory = umbracoContextFactory; - _globalSettings = globalSettings; - _hostingEnvironment = hostingEnvironment; - } - - /// - /// Begins to process a request. - /// - private void BeginRequest(HttpContextBase httpContext) - { - // write the trace output for diagnostics at the end of the request - httpContext.Trace.Write("UmbracoModule", "Umbraco request begins"); - - // ok, process - - // TODO: should we move this to after we've ensured we are processing a routable page? - // ensure there's an UmbracoContext registered for the current request - // registers the context reference so its disposed at end of request - var umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext(); - httpContext.DisposeOnPipelineCompleted(umbracoContextReference); - } - - /// - /// Processes the Umbraco Request - /// - /// - /// This will check if we are trying to route to the default back office page (i.e. ~/Umbraco/ or ~/Umbraco or ~/Umbraco/Default ) - /// and ensure that the MVC handler executes for that. This is required because the route for /Umbraco will never execute because - /// files/folders exist there and we cannot set the RouteCollection.RouteExistingFiles = true since that will muck a lot of other things up. - /// So we handle it here and explicitly execute the MVC controller. - /// - void ProcessRequest(HttpContextBase httpContext) - { - - var umbracoContext = Current.UmbracoContext; - - // do not process if this request is not a front-end routable page - var isRoutableAttempt = EnsureUmbracoRoutablePage(umbracoContext, httpContext); - - // raise event here - UmbracoModule.OnRouteAttempt(this, new RoutableAttemptEventArgs(isRoutableAttempt.Result, umbracoContext)); - if (isRoutableAttempt.Success == false) return; - } - - /// - /// Checks the current request and ensures that it is routable based on the structure of the request and URI - /// - internal Attempt EnsureUmbracoRoutablePage(IUmbracoContext context, HttpContextBase httpContext) - { - var uri = context.OriginalRequestUrl; - - var reason = EnsureRoutableOutcome.IsRoutable; - - //// ensure this is a document request - //if (!_routableDocumentLookup.IsDocumentRequest(httpContext, context.OriginalRequestUrl)) - //{ - // reason = EnsureRoutableOutcome.NotDocumentRequest; - //} - - // ensure the runtime is in the proper state - // and deal with needed redirects, etc - if (!EnsureRuntime(httpContext, uri)) - { - reason = EnsureRoutableOutcome.NotReady; - } - // ensure Umbraco has documents to serve - else if (!EnsureHasContent(context, httpContext)) - { - reason = EnsureRoutableOutcome.NoContent; - } - - return Attempt.If(reason == EnsureRoutableOutcome.IsRoutable, reason); - } - - // TODO: Where should this execute in netcore? This will have to be a middleware - // executing before UseRouting so that it is done before any endpoint routing takes place. - private bool EnsureRuntime(HttpContextBase httpContext, Uri uri) - { - var level = _runtime.Level; - switch (level) - { - // we should never handle Unknown nor Boot: the runtime boots in Application_Start - // and as long as it has not booted, no request other than the initial request is - // going to be served (see https://stackoverflow.com/a/21402100) - // we should never handle BootFailed: if boot failed, the pipeline should not run - // at all - case RuntimeLevel.Unknown: - case RuntimeLevel.Boot: - case RuntimeLevel.BootFailed: - throw new PanicException($"Unexpected runtime level: {level}."); - - case RuntimeLevel.Run: - // ok - return true; - - case RuntimeLevel.Install: - case RuntimeLevel.Upgrade: - - // NOTE: We have moved the logic that was here to netcore already - - return false; // cannot serve content - - default: - throw new NotSupportedException($"Unexpected runtime level: {level}."); - } - } - - // ensures Umbraco has at least one published node - // if not, rewrites to splash and return false - // if yes, return true - private bool EnsureHasContent(IUmbracoContext context, HttpContextBase httpContext) - { - if (context.Content.HasContent()) - return true; - - _logger.LogWarning("Umbraco has no content"); - - if (RouteTable.Routes[Constants.Web.NoContentRouteName] is Route route) - { - httpContext.RewritePath(route.Url); - } - - return false; - } - - /// - /// Rewrites to the default back office page. - /// - /// - private void RewriteToBackOfficeHandler(HttpContextBase context) - { - // GlobalSettings.Path has already been through IOHelper.ResolveUrl() so it begins with / and vdir (if any) - var rewritePath = _globalSettings.GetBackOfficePath(_hostingEnvironment).TrimEnd('/') + "/Default"; - // rewrite the path to the path of the handler (i.e. /umbraco/RenderMvc) - context.RewritePath(rewritePath, "", "", false); - - //if it is MVC we need to do something special, we are not using TransferRequest as this will - //require us to rewrite the path with query strings and then re-parse the query strings, this would - //also mean that we need to handle IIS 7 vs pre-IIS 7 differently. Instead we are just going to create - //an instance of the UrlRoutingModule and call it's PostResolveRequestCache method. This does: - // * Looks up the route based on the new rewritten URL - // * Creates the RequestContext with all route parameters and then executes the correct handler that matches the route - //we also cannot re-create this functionality because the setter for the HttpContext.Request.RequestContext is internal - //so really, this is pretty much the only way without using Server.TransferRequest and if we did that, we'd have to rethink - //a bunch of things! - var urlRouting = new UrlRoutingModule(); - urlRouting.PostResolveRequestCache(context); - } - - - - #region IHttpModule - - /// - /// Initialize the module, this will trigger for each new application - /// and there may be more than 1 application per application domain - /// - /// - public void Init(HttpApplication app) - { - app.BeginRequest += (sender, e) => - { - var httpContext = ((HttpApplication) sender).Context; - - BeginRequest(new HttpContextWrapper(httpContext)); - }; - - app.PostAuthenticateRequest += (sender, e) => - { - var httpContext = ((HttpApplication) sender).Context; - //ensure the thread culture is set - httpContext.User?.Identity?.EnsureCulture(); - }; - - app.PostResolveRequestCache += (sender, e) => - { - var httpContext = ((HttpApplication) sender).Context; - ProcessRequest(new HttpContextWrapper(httpContext)); - }; - - app.EndRequest += (sender, args) => - { - var httpContext = ((HttpApplication) sender).Context; - - UmbracoModule.OnEndRequest(this, new UmbracoRequestEventArgs(Current.UmbracoContext)); - }; - } - - public void Dispose() - { } - - #endregion - - - } -} diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs deleted file mode 100644 index 2f9c6d518a..0000000000 --- a/src/Umbraco.Web/UmbracoModule.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Web; -using Microsoft.Extensions.Logging; -using Umbraco.Core; -using Umbraco.Web.Composing; -using Umbraco.Web.Routing; - -namespace Umbraco.Web -{ - /// - /// Represents the main Umbraco module. - /// - /// - /// Register that one in web.config. - /// It will inject which contains most of the actual code. - /// - public class UmbracoModule : ModuleInjector - { - /// - /// Occurs when... - /// - internal static event EventHandler RouteAttempt; - - /// - /// Occurs when... - /// - public static event EventHandler EndRequest; - - /// - /// Triggers the RouteAttempt event. - /// - internal static void OnRouteAttempt(object sender, RoutableAttemptEventArgs args) - { - RouteAttempt?.Invoke(sender, args); - } - - /// - /// Triggers the EndRequest event. - /// - internal static void OnEndRequest(object sender, UmbracoRequestEventArgs args) - { - EndRequest?.Invoke(sender, args); - } - } -}