V13: Eaglery route domains for virtual page controllers (#16635)

* Do domain routing eagerly

* Cleanup

* Fix comment
This commit is contained in:
Mole
2024-06-20 11:25:02 +02:00
committed by Nikolaj Geisle
parent a686ba2a0e
commit 56710d5b5b

View File

@@ -8,7 +8,9 @@ using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Web.Common.Controllers;
using Umbraco.Cms.Web.Common.Routing;
using Umbraco.Cms.Web.Website.Controllers;
using Umbraco.Extensions;
@@ -37,6 +39,8 @@ internal class EagerMatcherPolicy : MatcherPolicy, IEndpointSelectorPolicy
private readonly IRuntimeState _runtimeState;
private readonly EndpointDataSource _endpointDataSource;
private readonly UmbracoRequestPaths _umbracoRequestPaths;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IPublishedRouter _publishedRouter;
private GlobalSettings _globalSettings;
private readonly Lazy<Endpoint> _installEndpoint;
private readonly Lazy<Endpoint> _renderEndpoint;
@@ -45,11 +49,15 @@ internal class EagerMatcherPolicy : MatcherPolicy, IEndpointSelectorPolicy
IRuntimeState runtimeState,
EndpointDataSource endpointDataSource,
UmbracoRequestPaths umbracoRequestPaths,
IOptionsMonitor<GlobalSettings> globalSettings)
IOptionsMonitor<GlobalSettings> globalSettings,
IUmbracoContextAccessor umbracoContextAccessor,
IPublishedRouter publishedRouter)
{
_runtimeState = runtimeState;
_endpointDataSource = endpointDataSource;
_umbracoRequestPaths = umbracoRequestPaths;
_umbracoContextAccessor = umbracoContextAccessor;
_publishedRouter = publishedRouter;
_globalSettings = globalSettings.CurrentValue;
globalSettings.OnChange(settings => _globalSettings = settings);
_installEndpoint = new Lazy<Endpoint>(GetInstallEndpoint);
@@ -112,11 +120,22 @@ internal class EagerMatcherPolicy : MatcherPolicy, IEndpointSelectorPolicy
ControllerActionDescriptor? controllerDescriptor = routeEndpoint.Metadata.GetMetadata<ControllerActionDescriptor>();
TypeInfo? controllerTypeInfo = controllerDescriptor?.ControllerTypeInfo;
if (controllerTypeInfo is not null &&
(controllerTypeInfo.IsType<RenderController>() || controllerTypeInfo.IsType<SurfaceController>()))
(controllerTypeInfo.IsType<RenderController>()
|| controllerTypeInfo.IsType<SurfaceController>()))
{
return;
}
// If it's an UmbracoPageController we need to do some domain routing.
// We need to do this in oder to handle cultures for our Dictionary.
// This is because UmbracoPublishedContentCultureProvider is ued to set the Thread.CurrentThread.CurrentUICulture
// The CultureProvider is run before the actual routing, this means that our UmbracoVirtualPageFilterAttribute is hit AFTER the culture is set.
// Meaning we have to route the domain part already now, this is not pretty, but it beats having to look for content we know doesn't exist.
if (controllerTypeInfo is not null && controllerTypeInfo.IsType<UmbracoPageController>())
{
await RouteVirtualRequestAsync(httpContext);
}
if (routeEndpoint.Order < lowestOrder)
{
// We have to ensure that the route is valid for the current request method.
@@ -153,6 +172,22 @@ internal class EagerMatcherPolicy : MatcherPolicy, IEndpointSelectorPolicy
}
}
private async Task RouteVirtualRequestAsync(HttpContext context)
{
if (_umbracoContextAccessor.TryGetUmbracoContext(out IUmbracoContext? umbracoContext) is false)
{
return;
}
IPublishedRequestBuilder requestBuilder =
await _publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
_publishedRouter.RouteDomain(requestBuilder);
// This is just a temporary RouteValues object just for culture which will be overwritten later
// so we can just use a dummy action descriptor.
var umbracoRouteValues = new UmbracoRouteValues(requestBuilder.Build(), new ControllerActionDescriptor());
context.Features.Set(umbracoRouteValues);
}
/// <summary>
/// Replaces the first endpoint candidate with the specified endpoint, invalidating all other candidates,
/// guaranteeing that the specified endpoint will be hit.