diff --git a/src/Umbraco.Web.Common/AspNetCore/ApplicationUrlRequestBeginNotificationHandler.cs b/src/Umbraco.Web.Common/AspNetCore/ApplicationUrlRequestBeginNotificationHandler.cs
new file mode 100644
index 0000000000..0472d31592
--- /dev/null
+++ b/src/Umbraco.Web.Common/AspNetCore/ApplicationUrlRequestBeginNotificationHandler.cs
@@ -0,0 +1,26 @@
+using Umbraco.Cms.Core.Events;
+using Umbraco.Cms.Core.Notifications;
+using Umbraco.Cms.Core.Web;
+
+namespace Umbraco.Cms.Web.Common.AspNetCore;
+
+///
+/// Notification handler which will listen to the , and ensure that
+/// the applicationUrl is set on the first request.
+///
+internal class ApplicationUrlRequestBeginNotificationHandler : INotificationHandler
+{
+ private readonly IRequestAccessor _requestAccessor;
+
+ public ApplicationUrlRequestBeginNotificationHandler(IRequestAccessor requestAccessor) =>
+ _requestAccessor = requestAccessor;
+
+ public void Handle(UmbracoRequestBeginNotification notification)
+ {
+ // If someone has replaced the AspNetCoreRequestAccessor we'll do nothing and assume they handle it themselves.
+ if (_requestAccessor is AspNetCoreRequestAccessor accessor)
+ {
+ accessor.EnsureApplicationUrl();
+ }
+ }
+}
diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs
index 38d67ff2f0..de47999835 100644
--- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs
+++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs
@@ -9,7 +9,7 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Web.Common.AspNetCore;
-public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler
+public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler, IDisposable
{
private readonly ISet _applicationUrls = new HashSet();
private readonly IHttpContextAccessor _httpContextAccessor;
@@ -18,6 +18,7 @@ public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler<
private object _initLocker = new();
private bool _isInit;
private WebRoutingSettings _webRoutingSettings;
+ private readonly IDisposable? _onChangeDisposable;
///
/// Initializes a new instance of the class.
@@ -28,20 +29,19 @@ public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler<
{
_httpContextAccessor = httpContextAccessor;
_webRoutingSettings = webRoutingSettings.CurrentValue;
- webRoutingSettings.OnChange(x => _webRoutingSettings = x);
+ _onChangeDisposable = webRoutingSettings.OnChange(x => _webRoutingSettings = x);
}
///
- /// 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
+ ///
+ /// This is now a NoOp, and is no longer used, instead ApplicationUrlRequestBeginNotificationHandler is used
+ ///
///
+ [Obsolete("This is no longer used, AspNetCoreRequestAccessor will no longer implement INotificationHandler in V12, see ApplicationUrlRequestBeginNotificationHandler instead.")]
public void Handle(UmbracoRequestBeginNotification notification)
- => LazyInitializer.EnsureInitialized(ref _hasAppUrl, ref _isInit, ref _initLocker, () =>
- {
- GetApplicationUrl();
- return true;
- });
+ {
+ // NoOP
+ }
///
public string GetRequestValue(string name) => GetFormValue(name) ?? GetQueryStringValue(name);
@@ -54,6 +54,17 @@ public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler<
? new Uri(_httpContextAccessor.HttpContext.Request.GetEncodedUrl())
: null;
+ ///
+ /// Ensure that the ApplicationUrl is set on the first request, this is using a LazyInitializer, so the code will only be run the first time
+ ///
+ /// TODO: This doesn't belong here, the GetApplicationUrl doesn't belong to IRequestAccessor
+ internal void EnsureApplicationUrl() =>
+ LazyInitializer.EnsureInitialized(ref _hasAppUrl, ref _isInit, ref _initLocker, () =>
+ {
+ GetApplicationUrl();
+ return true;
+ });
+
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
@@ -63,7 +74,7 @@ public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler<
// 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))
+ if (_webRoutingSettings.UmbracoApplicationUrl is not null)
{
return new Uri(_webRoutingSettings.UmbracoApplicationUrl);
}
@@ -96,4 +107,6 @@ public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler<
return request.Form[name];
}
+
+ public void Dispose() => _onChangeDisposable?.Dispose();
}
diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs
index 40b84a0987..d454e5d6c5 100644
--- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs
+++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs
@@ -298,6 +298,7 @@ public static partial class UmbracoBuilderExtensions
// AspNetCore specific services
builder.Services.AddUnique();
builder.AddNotificationHandler();
+ builder.AddNotificationHandler();
// Password hasher
builder.Services.AddUnique();