Skip to content

Commit

Permalink
V13: Eaglery route domains for virtual page controllers (#16635)
Browse files Browse the repository at this point in the history
* Do domain routing eagerly

* Cleanup

* Fix comment
  • Loading branch information
nikolajlauridsen authored and Zeegaan committed Jun 20, 2024
1 parent a686ba2 commit 56710d5
Showing 1 changed file with 37 additions and 2 deletions.
39 changes: 37 additions & 2 deletions src/Umbraco.Web.Website/Routing/EagerMatcherPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
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;

Expand Down Expand Up @@ -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;
Expand All @@ -45,11 +49,15 @@ public EagerMatcherPolicy(
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);
Expand Down Expand Up @@ -112,11 +120,22 @@ public async Task ApplyAsync(HttpContext httpContext, CandidateSet candidates)
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.
Expand Down Expand Up @@ -153,6 +172,22 @@ public async Task ApplyAsync(HttpContext httpContext, CandidateSet candidates)
}
}

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.
Expand Down

0 comments on commit 56710d5

Please sign in to comment.