diff --git a/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs b/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs
index 46571f5d65..500bd65f82 100644
--- a/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs
+++ b/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs
@@ -49,7 +49,7 @@ namespace Umbraco.Web.Routing
}
IPublishedContent node = null;
- var path = frequest.Uri.GetAbsolutePathDecoded();
+ var path = frequest.AbsolutePathDecoded;
var nodeId = -1;
diff --git a/src/Umbraco.Core/Routing/ContentFinderByRedirectUrl.cs b/src/Umbraco.Core/Routing/ContentFinderByRedirectUrl.cs
index 38f04d1ddb..e3c5b28a2a 100644
--- a/src/Umbraco.Core/Routing/ContentFinderByRedirectUrl.cs
+++ b/src/Umbraco.Core/Routing/ContentFinderByRedirectUrl.cs
@@ -51,8 +51,8 @@ namespace Umbraco.Web.Routing
}
var route = frequest.Domain != null
- ? frequest.Domain.ContentId + DomainUtilities.PathRelativeToDomain(frequest.Domain.Uri, frequest.Uri.GetAbsolutePathDecoded())
- : frequest.Uri.GetAbsolutePathDecoded();
+ ? frequest.Domain.ContentId + DomainUtilities.PathRelativeToDomain(frequest.Domain.Uri, frequest.AbsolutePathDecoded)
+ : frequest.AbsolutePathDecoded;
IRedirectUrl redirectUrl = _redirectUrlService.GetMostRecentRedirectUrl(route, frequest.Culture);
diff --git a/src/Umbraco.Core/Routing/ContentFinderByUrl.cs b/src/Umbraco.Core/Routing/ContentFinderByUrl.cs
index 27893cd3de..c20cf9fd85 100644
--- a/src/Umbraco.Core/Routing/ContentFinderByUrl.cs
+++ b/src/Umbraco.Core/Routing/ContentFinderByUrl.cs
@@ -44,11 +44,11 @@ namespace Umbraco.Web.Routing
string route;
if (frequest.Domain != null)
{
- route = frequest.Domain.ContentId + DomainUtilities.PathRelativeToDomain(frequest.Domain.Uri, frequest.Uri.GetAbsolutePathDecoded());
+ route = frequest.Domain.ContentId + DomainUtilities.PathRelativeToDomain(frequest.Domain.Uri, frequest.AbsolutePathDecoded);
}
else
{
- route = frequest.Uri.GetAbsolutePathDecoded();
+ route = frequest.AbsolutePathDecoded;
}
IPublishedContent node = FindContent(frequest, route);
diff --git a/src/Umbraco.Core/Routing/ContentFinderByUrlAlias.cs b/src/Umbraco.Core/Routing/ContentFinderByUrlAlias.cs
index 770fdf4003..4745ea8cd3 100644
--- a/src/Umbraco.Core/Routing/ContentFinderByUrlAlias.cs
+++ b/src/Umbraco.Core/Routing/ContentFinderByUrlAlias.cs
@@ -60,7 +60,7 @@ namespace Umbraco.Web.Routing
umbCtx.Content,
frequest.Domain != null ? frequest.Domain.ContentId : 0,
frequest.Culture,
- frequest.Uri.GetAbsolutePathDecoded());
+ frequest.AbsolutePathDecoded);
if (node != null)
{
diff --git a/src/Umbraco.Core/Routing/ContentFinderByUrlAndTemplate.cs b/src/Umbraco.Core/Routing/ContentFinderByUrlAndTemplate.cs
index c6bd4f383d..2e69446d68 100644
--- a/src/Umbraco.Core/Routing/ContentFinderByUrlAndTemplate.cs
+++ b/src/Umbraco.Core/Routing/ContentFinderByUrlAndTemplate.cs
@@ -49,7 +49,7 @@ namespace Umbraco.Web.Routing
/// If successful, also assigns the template.
public override bool TryFindContent(IPublishedRequestBuilder frequest)
{
- var path = frequest.Uri.GetAbsolutePathDecoded();
+ var path = frequest.AbsolutePathDecoded;
if (frequest.Domain != null)
{
diff --git a/src/Umbraco.Core/Routing/DomainUtilities.cs b/src/Umbraco.Core/Routing/DomainUtilities.cs
index fa5d84836d..0d14b26396 100644
--- a/src/Umbraco.Core/Routing/DomainUtilities.cs
+++ b/src/Umbraco.Core/Routing/DomainUtilities.cs
@@ -364,9 +364,7 @@ namespace Umbraco.Web.Routing
/// The path part relative to the uri of the domain.
/// Eg the relative part of /foo/bar/nil to domain example.com/foo is /bar/nil.
public static string PathRelativeToDomain(Uri domainUri, string path)
- {
- return path.Substring(domainUri.GetAbsolutePathDecoded().Length).EnsureStartsWith('/');
- }
+ => path.Substring(domainUri.GetAbsolutePathDecoded().Length).EnsureStartsWith('/');
#endregion
}
diff --git a/src/Umbraco.Core/Routing/IPublishedRequestBuilder.cs b/src/Umbraco.Core/Routing/IPublishedRequestBuilder.cs
index ced443a89c..180b6825f2 100644
--- a/src/Umbraco.Core/Routing/IPublishedRequestBuilder.cs
+++ b/src/Umbraco.Core/Routing/IPublishedRequestBuilder.cs
@@ -18,6 +18,11 @@ namespace Umbraco.Web.Routing
/// The cleaned up Uri has no virtual directory, no trailing slash, no .aspx extension, etc.
Uri Uri { get; }
+ ///
+ /// Gets the decoded absolute path of the
+ ///
+ string AbsolutePathDecoded { get; }
+
///
/// Gets the assigned (if any)
///
diff --git a/src/Umbraco.Core/Routing/PublishedRequestBuilder.cs b/src/Umbraco.Core/Routing/PublishedRequestBuilder.cs
index faa793c7ff..9ed8a1ee10 100644
--- a/src/Umbraco.Core/Routing/PublishedRequestBuilder.cs
+++ b/src/Umbraco.Core/Routing/PublishedRequestBuilder.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
+using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Services;
@@ -26,12 +27,16 @@ namespace Umbraco.Web.Routing
public PublishedRequestBuilder(Uri uri, IFileService fileService)
{
Uri = uri;
+ AbsolutePathDecoded = uri.GetAbsolutePathDecoded();
_fileService = fileService;
}
///
public Uri Uri { get; }
+ ///
+ public string AbsolutePathDecoded { get; }
+
///
public DomainAndUri Domain { get; private set; }
diff --git a/src/Umbraco.Core/Routing/UriUtility.cs b/src/Umbraco.Core/Routing/UriUtility.cs
index 8de78dfbf5..96325d1289 100644
--- a/src/Umbraco.Core/Routing/UriUtility.cs
+++ b/src/Umbraco.Core/Routing/UriUtility.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Text;
using Umbraco.Core;
using Umbraco.Core.Configuration;
@@ -88,6 +88,10 @@ namespace Umbraco.Web
// ie no virtual directory, no .aspx, lowercase...
public Uri UriToUmbraco(Uri uri)
{
+ // TODO: Ideally we do this witout so many string allocations, we can use
+ // techniques like StringSegment and Span. This is critical code that executes on every request.
+ // not really sure we need ToLower.
+
// note: no need to decode uri here because we're returning a uri
// so it will be re-encoded anyway
var path = uri.GetSafeAbsolutePath();
@@ -95,23 +99,11 @@ namespace Umbraco.Web
path = path.ToLower();
path = ToAppRelative(path); // strip vdir if any
- //we need to check if the path is /default.aspx because this will occur when using a
- //web server pre IIS 7 when requesting the root document
- //if this is the case we need to change it to '/'
- if (path.StartsWith("/default.aspx", StringComparison.InvariantCultureIgnoreCase))
- {
- string rempath = path.Substring("/default.aspx".Length, path.Length - "/default.aspx".Length);
- path = rempath.StartsWith("/") ? rempath : "/" + rempath;
- }
if (path != "/")
{
path = path.TrimEnd('/');
}
- //if any part of the path contains .aspx, replace it with nothing.
- //sometimes .aspx is not at the end since we might have /home/sub1.aspx/customtemplate
- path = path.Replace(".aspx", "");
-
return uri.Rewrite(path);
}
diff --git a/src/Umbraco.Core/UriExtensions.cs b/src/Umbraco.Core/UriExtensions.cs
index 497159309a..53bf2d6d92 100644
--- a/src/Umbraco.Core/UriExtensions.cs
+++ b/src/Umbraco.Core/UriExtensions.cs
@@ -61,7 +61,9 @@ namespace Umbraco.Core
public static string GetSafeAbsolutePath(this Uri uri)
{
if (uri.IsAbsoluteUri)
+ {
return uri.AbsolutePath;
+ }
// cannot get .AbsolutePath on relative uri (InvalidOperation)
var s = uri.OriginalString;
diff --git a/src/Umbraco.Infrastructure/Routing/ContentFinderByConfigured404.cs b/src/Umbraco.Infrastructure/Routing/ContentFinderByConfigured404.cs
index 5634fa4a93..bc9f9f3857 100644
--- a/src/Umbraco.Infrastructure/Routing/ContentFinderByConfigured404.cs
+++ b/src/Umbraco.Infrastructure/Routing/ContentFinderByConfigured404.cs
@@ -61,7 +61,7 @@ namespace Umbraco.Web.Routing
}
else
{
- var route = frequest.Uri.GetAbsolutePathDecoded();
+ var route = frequest.AbsolutePathDecoded;
var pos = route.LastIndexOf('/');
IPublishedContent node = null;
while (pos > 1)
diff --git a/src/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj b/src/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj
index aa39070cc7..bdb703753d 100644
--- a/src/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj
+++ b/src/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj
index c1d0fe3758..dbb3fa1137 100644
--- a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj
+++ b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj
@@ -59,7 +59,7 @@
-
+
all
diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/HijackedRouteEvaluatorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/HijackedRouteEvaluatorTests.cs
index 5543a8920a..2d96476b30 100644
--- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/HijackedRouteEvaluatorTests.cs
+++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/HijackedRouteEvaluatorTests.cs
@@ -79,13 +79,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Routing
}
[TestCase("Index", "RenderNotFound", null, false)]
- [TestCase("index", "Render", "Index", true)]
- [TestCase("Index", "Render1", "Index", true)]
- [TestCase("Index", "render2", "Index", true)]
- [TestCase("NotFound", "Render", "Index", true)]
- [TestCase("NotFound", "Render1", "Index", true)]
- [TestCase("NotFound", "Render2", "Index", true)]
- [TestCase("Custom", "Render1", "Custom", true)]
+ [TestCase("index", "Render", nameof(RenderController.Index), true)]
+ [TestCase("Index", "Render1", nameof(RenderController.Index), true)]
+ [TestCase("Index", "render2", nameof(Render2Controller.Index), true)]
+ [TestCase("NotFound", "Render", nameof(RenderController.Index), true)]
+ [TestCase("NotFound", "Render1", nameof(Render1Controller.Index), true)]
+ [TestCase("NotFound", "Render2", nameof(Render2Controller.Index), true)]
+ [TestCase("Custom", "Render1", nameof(Render1Controller.Custom), true)]
public void Matches_Controller(string action, string controller, string resultAction, bool matches)
{
var evaluator = new HijackedRouteEvaluator(
diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs
new file mode 100644
index 0000000000..0b9e1d6420
--- /dev/null
+++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs
@@ -0,0 +1,170 @@
+using System;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc.ViewEngines;
+using Microsoft.AspNetCore.Routing;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Extensions.Options;
+using Moq;
+using NUnit.Framework;
+using Umbraco.Core;
+using Umbraco.Core.Configuration.Models;
+using Umbraco.Core.Models.PublishedContent;
+using Umbraco.Extensions;
+using Umbraco.Tests.TestHelpers;
+using Umbraco.Web;
+using Umbraco.Web.Common.Controllers;
+using Umbraco.Web.Common.Routing;
+using Umbraco.Web.PublishedCache;
+using Umbraco.Web.Routing;
+using Umbraco.Web.Website.Controllers;
+using Umbraco.Web.Website.Routing;
+
+namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Routing
+{
+ [TestFixture]
+ public class UmbracoRouteValueTransformerTests
+ {
+ private IOptions GetGlobalSettings() => Options.Create(new GlobalSettings());
+
+ private UmbracoRouteValueTransformer GetTransformerWithRunState(
+ IUmbracoContextAccessor ctx,
+ IRoutableDocumentFilter filter = null,
+ IPublishedRouter router = null,
+ IUmbracoRouteValuesFactory routeValuesFactory = null)
+ => GetTransformer(ctx, Mock.Of(x => x.Level == RuntimeLevel.Run), filter, router, routeValuesFactory);
+
+ private UmbracoRouteValueTransformer GetTransformer(
+ IUmbracoContextAccessor ctx,
+ IRuntimeState state,
+ IRoutableDocumentFilter filter = null,
+ IPublishedRouter router = null,
+ IUmbracoRouteValuesFactory routeValuesFactory = null)
+ {
+ var transformer = new UmbracoRouteValueTransformer(
+ new NullLogger(),
+ ctx,
+ router ?? Mock.Of(),
+ GetGlobalSettings(),
+ TestHelper.GetHostingEnvironment(),
+ state,
+ routeValuesFactory ?? Mock.Of(),
+ filter ?? Mock.Of(x => x.IsDocumentRequest(It.IsAny()) == true));
+
+ return transformer;
+ }
+
+ private IUmbracoContext GetUmbracoContext(bool hasContent)
+ {
+ IPublishedContentCache publishedContent = Mock.Of(x => x.HasContent() == hasContent);
+ var uri = new Uri("http://example.com");
+
+ IUmbracoContext umbracoContext = Mock.Of(x =>
+ x.Content == publishedContent
+ && x.OriginalRequestUrl == uri
+ && x.CleanedUmbracoUrl == uri);
+
+ return umbracoContext;
+ }
+
+ private UmbracoRouteValues GetRouteValues(IPublishedRequest request)
+ => new UmbracoRouteValues(
+ request,
+ ControllerExtensions.GetControllerName(),
+ typeof(TestController));
+
+ private IUmbracoRouteValuesFactory GetRouteValuesFactory(IPublishedRequest request)
+ => Mock.Of(x => x.Create(It.IsAny(), It.IsAny(), It.IsAny()) == GetRouteValues(request));
+
+ private IPublishedRouter GetRouter(IPublishedRequest request)
+ => Mock.Of(x => x.RouteRequestAsync(It.IsAny(), It.IsAny()) == Task.FromResult(request));
+
+ [Test]
+ public async Task Noop_When_Runtime_Level_Not_Run()
+ {
+ UmbracoRouteValueTransformer transformer = GetTransformer(
+ Mock.Of(x => x.UmbracoContext == null),
+ Mock.Of());
+
+ RouteValueDictionary result = await transformer.TransformAsync(new DefaultHttpContext(), new RouteValueDictionary());
+ Assert.AreEqual(0, result.Count);
+ }
+
+ [Test]
+ public async Task Noop_When_No_Umbraco_Context()
+ {
+ UmbracoRouteValueTransformer transformer = GetTransformerWithRunState(
+ Mock.Of(x => x.UmbracoContext == null));
+
+ RouteValueDictionary result = await transformer.TransformAsync(new DefaultHttpContext(), new RouteValueDictionary());
+ Assert.AreEqual(0, result.Count);
+ }
+
+ [Test]
+ public async Task Noop_When_Not_Document_Request()
+ {
+ UmbracoRouteValueTransformer transformer = GetTransformerWithRunState(
+ Mock.Of(x => x.UmbracoContext == Mock.Of()),
+ Mock.Of(x => x.IsDocumentRequest(It.IsAny()) == false));
+
+ RouteValueDictionary result = await transformer.TransformAsync(new DefaultHttpContext(), new RouteValueDictionary());
+ Assert.AreEqual(0, result.Count);
+ }
+
+ [Test]
+ public async Task NoContentController_Values_When_No_Content()
+ {
+ IUmbracoContext umbracoContext = GetUmbracoContext(false);
+
+ UmbracoRouteValueTransformer transformer = GetTransformerWithRunState(
+ Mock.Of(x => x.UmbracoContext == umbracoContext));
+
+ RouteValueDictionary result = await transformer.TransformAsync(new DefaultHttpContext(), new RouteValueDictionary());
+ Assert.AreEqual(2, result.Count);
+ Assert.AreEqual(ControllerExtensions.GetControllerName(), result["controller"]);
+ Assert.AreEqual(nameof(RenderNoContentController.Index), result["action"]);
+ }
+
+ [Test]
+ public async Task Assigns_PublishedRequest_To_UmbracoContext()
+ {
+ IUmbracoContext umbracoContext = GetUmbracoContext(true);
+ IPublishedRequest request = Mock.Of();
+
+ UmbracoRouteValueTransformer transformer = GetTransformerWithRunState(
+ Mock.Of(x => x.UmbracoContext == umbracoContext),
+ router: GetRouter(request),
+ routeValuesFactory: GetRouteValuesFactory(request));
+
+ RouteValueDictionary result = await transformer.TransformAsync(new DefaultHttpContext(), new RouteValueDictionary());
+ Assert.AreEqual(request, umbracoContext.PublishedRequest);
+ }
+
+ [Test]
+ public async Task Assigns_Values_To_RouteValueDictionary()
+ {
+ IUmbracoContext umbracoContext = GetUmbracoContext(true);
+ IPublishedRequest request = Mock.Of();
+ UmbracoRouteValues routeValues = GetRouteValues(request);
+
+ UmbracoRouteValueTransformer transformer = GetTransformerWithRunState(
+ Mock.Of(x => x.UmbracoContext == umbracoContext),
+ router: GetRouter(request),
+ routeValuesFactory: GetRouteValuesFactory(request));
+
+ RouteValueDictionary result = await transformer.TransformAsync(new DefaultHttpContext(), new RouteValueDictionary());
+
+ Assert.AreEqual(routeValues.ControllerName, result["controller"]);
+ Assert.AreEqual(routeValues.ActionName, result["action"]);
+ }
+
+ private class TestController : RenderController
+ {
+ public TestController(ILogger logger, ICompositeViewEngine compositeViewEngine, IUmbracoContextAccessor umbracoContextAccessor)
+ : base(logger, compositeViewEngine, umbracoContextAccessor)
+ {
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValuesFactoryTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValuesFactoryTests.cs
index ca5329a3f7..17ce59862f 100644
--- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValuesFactoryTests.cs
+++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValuesFactoryTests.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Routing;
@@ -18,16 +18,17 @@ using Umbraco.Web.Website.Routing;
namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Routing
{
+
[TestFixture]
public class UmbracoRouteValuesFactoryTests
{
- private UmbracoRouteValuesFactory GetFactory(IPublishedRouter router, out UmbracoRenderingDefaults renderingDefaults)
+ private UmbracoRouteValuesFactory GetFactory(out Mock publishedRouter, out UmbracoRenderingDefaults renderingDefaults)
{
var builder = new PublishedRequestBuilder(new Uri("https://example.com"), Mock.Of());
builder.SetPublishedContent(Mock.Of());
IPublishedRequest request = builder.Build();
- var publishedRouter = new Mock();
+ publishedRouter = new Mock();
publishedRouter.Setup(x => x.UpdateRequestToNotFound(It.IsAny()))
.Returns((IPublishedRequest r) => builder)
.Verifiable();
@@ -53,12 +54,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Routing
builder.SetPublishedContent(Mock.Of());
IPublishedRequest request = builder.Build();
- var publishedRouter = new Mock();
- publishedRouter.Setup(x => x.UpdateRequestToNotFound(It.IsAny()))
- .Returns((IPublishedRequest r) => builder)
- .Verifiable();
-
- UmbracoRouteValuesFactory factory = GetFactory(publishedRouter.Object, out _);
+ UmbracoRouteValuesFactory factory = GetFactory(out Mock publishedRouter, out _);
UmbracoRouteValues result = factory.Create(new DefaultHttpContext(), new RouteValueDictionary(), request);
@@ -74,7 +70,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Routing
builder.SetTemplate(Mock.Of());
IPublishedRequest request = builder.Build();
- UmbracoRouteValuesFactory factory = GetFactory(Mock.Of(), out UmbracoRenderingDefaults renderingDefaults);
+ UmbracoRouteValuesFactory factory = GetFactory(out _, out UmbracoRenderingDefaults renderingDefaults);
var routeVals = new RouteValueDictionary();
UmbracoRouteValues result = factory.Create(new DefaultHttpContext(), routeVals, request);
diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj
index e1f57262ff..fe9d41f681 100644
--- a/src/Umbraco.Tests/Umbraco.Tests.csproj
+++ b/src/Umbraco.Tests/Umbraco.Tests.csproj
@@ -112,7 +112,7 @@
-
+
@@ -307,7 +307,7 @@
-
+
diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs
index c5104c0fdc..cd38712aa0 100644
--- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs
+++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
@@ -61,7 +61,7 @@ namespace Umbraco.Web.Common.AspNetCore
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
+ // 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
diff --git a/src/Umbraco.Web.Common/Routing/IRoutableDocumentFilter.cs b/src/Umbraco.Web.Common/Routing/IRoutableDocumentFilter.cs
new file mode 100644
index 0000000000..b921918bf6
--- /dev/null
+++ b/src/Umbraco.Web.Common/Routing/IRoutableDocumentFilter.cs
@@ -0,0 +1,7 @@
+namespace Umbraco.Web.Common.Routing
+{
+ public interface IRoutableDocumentFilter
+ {
+ bool IsDocumentRequest(string absPath);
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Web.Common/Routing/RoutableDocumentFilter.cs b/src/Umbraco.Web.Common/Routing/RoutableDocumentFilter.cs
index dee90bbfba..18190f9ad9 100644
--- a/src/Umbraco.Web.Common/Routing/RoutableDocumentFilter.cs
+++ b/src/Umbraco.Web.Common/Routing/RoutableDocumentFilter.cs
@@ -20,7 +20,7 @@ namespace Umbraco.Web.Common.Routing
///
/// There are various checks to determine if this is a front-end request such as checking if the request is part of any reserved paths or existing MVC routes.
///
- public sealed class RoutableDocumentFilter
+ public sealed class RoutableDocumentFilter : IRoutableDocumentFilter
{
private readonly ConcurrentDictionary _routeChecks = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase);
private readonly GlobalSettings _globalSettings;
diff --git a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs
index f7d3e61664..e89a874d71 100644
--- a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs
+++ b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs
@@ -16,6 +16,7 @@ namespace Umbraco.Web
public class UmbracoContext : DisposableObjectSlim, IDisposeOnRequestEnd, IUmbracoContext
{
private readonly IHostingEnvironment _hostingEnvironment;
+ private readonly UriUtility _uriUtility;
private readonly ICookieManager _cookieManager;
private readonly IRequestAccessor _requestAccessor;
private readonly Lazy _publishedSnapshot;
@@ -23,6 +24,8 @@ namespace Umbraco.Web
private bool? _previewing;
private readonly IBackOfficeSecurity _backofficeSecurity;
private readonly UmbracoRequestPaths _umbracoRequestPaths;
+ private Uri _originalRequestUrl;
+ private Uri _cleanedUmbracoUrl;
// initializes a new instance of the UmbracoContext class
// internal for unit tests
@@ -43,8 +46,8 @@ namespace Umbraco.Web
throw new ArgumentNullException(nameof(publishedSnapshotService));
}
- VariationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor));
-
+ VariationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor));
+ _uriUtility = uriUtility;
_hostingEnvironment = hostingEnvironment;
_cookieManager = cookieManager;
_requestAccessor = requestAccessor;
@@ -56,15 +59,6 @@ namespace Umbraco.Web
// beware - we cannot expect a current user here, so detecting preview mode must be a lazy thing
_publishedSnapshot = new Lazy(() => publishedSnapshotService.CreatePublishedSnapshot(PreviewToken));
-
- // set the urls...
- // NOTE: The request will not be available during app startup so we can only set this to an absolute URL of localhost, this
- // is a work around to being able to access the UmbracoContext during application startup and this will also ensure that people
- // 'could' still generate URLs during startup BUT any domain driven URL generation will not work because it is NOT possible to get
- // the current domain during application startup.
- // see: http://issues.umbraco.org/issue/U4-1890
- OriginalRequestUrl = _requestAccessor.GetRequestUrl() ?? new Uri("http://localhost");
- CleanedUmbracoUrl = uriUtility.UriToUmbraco(OriginalRequestUrl);
}
///
@@ -79,10 +73,17 @@ namespace Umbraco.Web
internal Guid UmbracoRequestId { get; }
///
- public Uri OriginalRequestUrl { get; }
+ // set the urls lazily, no need to allocate until they are needed...
+ // NOTE: The request will not be available during app startup so we can only set this to an absolute URL of localhost, this
+ // is a work around to being able to access the UmbracoContext during application startup and this will also ensure that people
+ // 'could' still generate URLs during startup BUT any domain driven URL generation will not work because it is NOT possible to get
+ // the current domain during application startup.
+ // see: http://issues.umbraco.org/issue/U4-1890
+ public Uri OriginalRequestUrl => _originalRequestUrl ?? (_originalRequestUrl = _requestAccessor.GetRequestUrl() ?? new Uri("http://localhost"));
///
- public Uri CleanedUmbracoUrl { get; }
+ // set the urls lazily, no need to allocate until they are needed...
+ public Uri CleanedUmbracoUrl => _cleanedUmbracoUrl ?? (_cleanedUmbracoUrl = _uriUtility.UriToUmbraco(OriginalRequestUrl));
///
public IPublishedSnapshot PublishedSnapshot => _publishedSnapshot.Value;
diff --git a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs
index a641f32235..ca2f9e6161 100644
--- a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs
+++ b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs
@@ -41,7 +41,7 @@ namespace Umbraco.Web.Website.DependencyInjection
builder.Services.AddSingleton();
builder.Services.AddSingleton();
builder.Services.AddSingleton();
- builder.Services.AddSingleton();
+ builder.Services.AddSingleton();
builder.AddDistributedCache();
diff --git a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs
index 5d0c564df3..af23105099 100644
--- a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs
+++ b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs
@@ -34,7 +34,7 @@ namespace Umbraco.Web.Website.Routing
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IRuntimeState _runtime;
private readonly IUmbracoRouteValuesFactory _routeValuesFactory;
- private readonly RoutableDocumentFilter _routableDocumentFilter;
+ private readonly IRoutableDocumentFilter _routableDocumentFilter;
///
/// Initializes a new instance of the class.
@@ -47,16 +47,21 @@ namespace Umbraco.Web.Website.Routing
IHostingEnvironment hostingEnvironment,
IRuntimeState runtime,
IUmbracoRouteValuesFactory routeValuesFactory,
- RoutableDocumentFilter routableDocumentFilter)
+ IRoutableDocumentFilter routableDocumentFilter)
{
- _logger = logger;
- _umbracoContextAccessor = umbracoContextAccessor;
- _publishedRouter = publishedRouter;
+ if (globalSettings is null)
+ {
+ throw new System.ArgumentNullException(nameof(globalSettings));
+ }
+
+ _logger = logger ?? throw new System.ArgumentNullException(nameof(logger));
+ _umbracoContextAccessor = umbracoContextAccessor ?? throw new System.ArgumentNullException(nameof(umbracoContextAccessor));
+ _publishedRouter = publishedRouter ?? throw new System.ArgumentNullException(nameof(publishedRouter));
_globalSettings = globalSettings.Value;
- _hostingEnvironment = hostingEnvironment;
- _runtime = runtime;
- _routeValuesFactory = routeValuesFactory;
- _routableDocumentFilter = routableDocumentFilter;
+ _hostingEnvironment = hostingEnvironment ?? throw new System.ArgumentNullException(nameof(hostingEnvironment));
+ _runtime = runtime ?? throw new System.ArgumentNullException(nameof(runtime));
+ _routeValuesFactory = routeValuesFactory ?? throw new System.ArgumentNullException(nameof(routeValuesFactory));
+ _routableDocumentFilter = routableDocumentFilter ?? throw new System.ArgumentNullException(nameof(routableDocumentFilter));
}
///
@@ -113,9 +118,10 @@ namespace Umbraco.Web.Website.Routing
// an immutable object. The only way to make this better would be to have a RouteRequest
// as part of UmbracoContext but then it will require a PublishedRouter dependency so not sure that's worth it.
// Maybe could be a one-time Set method instead?
- IPublishedRequest publishedRequest = umbracoContext.PublishedRequest = await _publishedRouter.RouteRequestAsync(requestBuilder, new RouteRequestOptions(RouteDirection.Inbound));
+ IPublishedRequest routedRequest = await _publishedRouter.RouteRequestAsync(requestBuilder, new RouteRequestOptions(RouteDirection.Inbound));
+ umbracoContext.PublishedRequest = routedRequest;
- return publishedRequest;
+ return routedRequest;
}
}
}
diff --git a/src/Umbraco.Web/UmbracoContext.cs b/src/Umbraco.Web/UmbracoContext.cs
index 7461364d3f..92a480bc45 100644
--- a/src/Umbraco.Web/UmbracoContext.cs
+++ b/src/Umbraco.Web/UmbracoContext.cs
@@ -62,7 +62,6 @@ namespace Umbraco.Web
// 'could' still generate URLs during startup BUT any domain driven URL generation will not work because it is NOT possible to get
// the current domain during application startup.
// see: http://issues.umbraco.org/issue/U4-1890
- //
OriginalRequestUrl = GetRequestFromContext()?.Url ?? new Uri("http://localhost");
CleanedUmbracoUrl = uriUtility.UriToUmbraco(OriginalRequestUrl);
}