diff --git a/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoBackOffice/Index.cshtml b/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoBackOffice/Index.cshtml
index a838386653..3ef3d0999b 100644
--- a/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoBackOffice/Index.cshtml
+++ b/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoBackOffice/Index.cshtml
@@ -28,7 +28,7 @@
-
+
Umbraco
diff --git a/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoLogin/Index.cshtml b/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoLogin/Index.cshtml
index 0cc86a50be..90bf8d3598 100644
--- a/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoLogin/Index.cshtml
+++ b/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoLogin/Index.cshtml
@@ -40,7 +40,7 @@
-
+
Umbraco
diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs
index 33f7a9d4e2..2070b59bb7 100644
--- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs
+++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs
@@ -1,6 +1,7 @@
using System.Data.Common;
using System.Net.Http.Headers;
using System.Reflection;
+using System.Runtime.CompilerServices;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection.Infrastructure;
using Microsoft.AspNetCore.Hosting;
@@ -326,23 +327,40 @@ public static partial class UmbracoBuilderExtensions
return builder;
}
- // TODO: Does this need to exist and/or be public?
+ [Obsolete("This is not necessary any more. This will be removed in v16")]
public static IUmbracoBuilder AddWebServer(this IUmbracoBuilder builder)
{
- // TODO: We need to figure out why this is needed and fix those endpoints to not need them, we don't want to change global things
- // If using Kestrel: https://stackoverflow.com/a/55196057
builder.Services.Configure(options =>
{
options.AllowSynchronousIO = true;
});
- builder.Services.Configure(options =>
- {
- options.AllowSynchronousIO = true;
- });
+ try
+ {
+ // See https://github.com/umbraco/Umbraco-CMS/pull/17886. This is a workaround for non-windows machines
+ // they won't have IIS available and trying to set this option will throw an exception.
+ //
+ // We're deferring this call to a method because if we just try to set the options here, we still get a
+ // TypeLoadException on non-windows machines.
+ // This workaround came from this comment: https://stackoverflow.com/a/3346975
+ AllowSynchronousIOForIIS(builder);
+ }
+ catch (TypeLoadException)
+ {
+ // Ignoring this exception because it's expected on non-windows machines
+ }
return builder;
}
+ // Prevents the compiler from inlining the method
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void AllowSynchronousIOForIIS(IUmbracoBuilder builder) =>
+ builder.Services.Configure(
+ options =>
+ {
+ options.AllowSynchronousIO = true;
+ });
+
private static IProfiler GetWebProfiler(IConfiguration config, IHttpContextAccessor httpContextAccessor)
{
var isDebug = config.GetValue($"{Constants.Configuration.ConfigHosting}:Debug");
diff --git a/src/Umbraco.Web.Common/Routing/UmbracoVirtualPageRoute.cs b/src/Umbraco.Web.Common/Routing/UmbracoVirtualPageRoute.cs
index 9813cf3212..f8bbd8ec76 100644
--- a/src/Umbraco.Web.Common/Routing/UmbracoVirtualPageRoute.cs
+++ b/src/Umbraco.Web.Common/Routing/UmbracoVirtualPageRoute.cs
@@ -5,8 +5,10 @@ using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
+using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Routing;
+using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Web.Common.Controllers;
using Umbraco.Cms.Web.Common.Extensions;
@@ -21,6 +23,7 @@ public class UmbracoVirtualPageRoute : IUmbracoVirtualPageRoute
private readonly LinkParser _linkParser;
private readonly UriUtility _uriUtility;
private readonly IPublishedRouter _publishedRouter;
+ private readonly IUmbracoContextAccessor _umbracoContextAccessor;
///
/// Constructor.
@@ -29,16 +32,29 @@ public class UmbracoVirtualPageRoute : IUmbracoVirtualPageRoute
/// The link parser.
/// The Uri utility.
/// The published router.
+ /// The umbraco context accessor.
public UmbracoVirtualPageRoute(
EndpointDataSource endpointDataSource,
LinkParser linkParser,
UriUtility uriUtility,
- IPublishedRouter publishedRouter)
+ IPublishedRouter publishedRouter,
+ IUmbracoContextAccessor umbracoContextAccessor)
{
_endpointDataSource = endpointDataSource;
_linkParser = linkParser;
_uriUtility = uriUtility;
_publishedRouter = publishedRouter;
+ _umbracoContextAccessor = umbracoContextAccessor;
+ }
+
+ [Obsolete("Please use constructor that takes an IUmbracoContextAccessor instead, scheduled for removal in v17")]
+ public UmbracoVirtualPageRoute(
+ EndpointDataSource endpointDataSource,
+ LinkParser linkParser,
+ UriUtility uriUtility,
+ IPublishedRouter publishedRouter)
+ : this(endpointDataSource, linkParser, uriUtility, publishedRouter, StaticServiceProvider.Instance.GetRequiredService())
+ {
}
///
@@ -157,7 +173,8 @@ public class UmbracoVirtualPageRoute : IUmbracoVirtualPageRoute
requestBuilder.SetPublishedContent(publishedContent);
_publishedRouter.RouteDomain(requestBuilder);
- return requestBuilder.Build();
+ // Ensure the culture and domain is set correctly for the published request
+ return await _publishedRouter.RouteRequestAsync(requestBuilder, new RouteRequestOptions(Core.Routing.RouteDirection.Inbound));
}
///
@@ -171,6 +188,12 @@ public class UmbracoVirtualPageRoute : IUmbracoVirtualPageRoute
{
IPublishedRequest publishedRequest = await CreatePublishedRequest(httpContext, publishedContent);
+ // Ensure the published request is set to the UmbracoContext
+ if (_umbracoContextAccessor.TryGetUmbracoContext(out IUmbracoContext? umbracoContext))
+ {
+ umbracoContext.PublishedRequest = publishedRequest;
+ }
+
var umbracoRouteValues = new UmbracoRouteValues(
publishedRequest,
controllerActionDescriptor);
diff --git a/src/Umbraco.Web.UI.Login/index.html b/src/Umbraco.Web.UI.Login/index.html
index b5845c773c..d4d93503e4 100644
--- a/src/Umbraco.Web.UI.Login/index.html
+++ b/src/Umbraco.Web.UI.Login/index.html
@@ -5,7 +5,7 @@
-
+
Umbraco
diff --git a/src/Umbraco.Web/HealthCheck/Checks/Security/UmbracoApplicationUrlCheck.cs b/src/Umbraco.Web/HealthCheck/Checks/Security/UmbracoApplicationUrlCheck.cs
deleted file mode 100644
index bc14f43235..0000000000
--- a/src/Umbraco.Web/HealthCheck/Checks/Security/UmbracoApplicationUrlCheck.cs
+++ /dev/null
@@ -1,109 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Umbraco.Core;
-using Umbraco.Core.Configuration.UmbracoSettings;
-using Umbraco.Core.IO;
-using Umbraco.Core.Services;
-using Umbraco.Web.HealthCheck.Checks.Config;
-
-namespace Umbraco.Web.HealthCheck.Checks.Security
-{
- [HealthCheck(
- "6708CA45-E96E-40B8-A40A-0607C1CA7F28",
- "Application URL Configuration",
- Description = "Checks if the Umbraco application URL is configured for your site.",
- Group = "Security")]
- public class UmbracoApplicationUrlCheck : HealthCheck
- {
- private readonly ILocalizedTextService _textService;
- private readonly IRuntimeState _runtime;
- private readonly IUmbracoSettingsSection _settings;
-
- private const string SetApplicationUrlAction = "setApplicationUrl";
-
- public UmbracoApplicationUrlCheck(ILocalizedTextService textService, IRuntimeState runtime, IUmbracoSettingsSection settings)
- {
- _textService = textService;
- _runtime = runtime;
- _settings = settings;
- }
-
- ///
- /// Executes the action and returns its status
- ///
- ///
- ///
- public override HealthCheckStatus ExecuteAction(HealthCheckAction action)
- {
- switch (action.Alias)
- {
- case SetApplicationUrlAction:
- return SetUmbracoApplicationUrl();
- default:
- throw new InvalidOperationException("UmbracoApplicationUrlCheck action requested is either not executable or does not exist");
- }
- }
-
- public override IEnumerable GetStatus()
- {
- //return the statuses
- return new[] { CheckUmbracoApplicationUrl() };
- }
-
- private HealthCheckStatus CheckUmbracoApplicationUrl()
- {
- var url = _settings.WebRouting.UmbracoApplicationUrl;
-
- string resultMessage;
- StatusResultType resultType;
- var actions = new List();
-
- if (url.IsNullOrWhiteSpace())
- {
- resultMessage = _textService.Localize("healthcheck", "umbracoApplicationUrlCheckResultFalse");
- resultType = StatusResultType.Warning;
-
- actions.Add(new HealthCheckAction(SetApplicationUrlAction, Id)
- {
- Name = _textService.Localize("healthcheck", "umbracoApplicationUrlConfigureButton"),
- Description = _textService.Localize("healthcheck", "umbracoApplicationUrlConfigureDescription")
- });
- }
- else
- {
- resultMessage = _textService.Localize("healthcheck", "umbracoApplicationUrlCheckResultTrue", new[] { url });
- resultType = StatusResultType.Success;
- }
-
- return new HealthCheckStatus(resultMessage)
- {
- ResultType = resultType,
- Actions = actions
- };
- }
-
- private HealthCheckStatus SetUmbracoApplicationUrl()
- {
- var configFilePath = IOHelper.MapPath("~/config/umbracoSettings.config");
- const string xPath = "/settings/web.routing/@umbracoApplicationUrl";
- var configurationService = new ConfigurationService(configFilePath, xPath, _textService);
- var urlValue = _runtime.ApplicationUrl.ToString();
- var updateConfigFile = configurationService.UpdateConfigFile(urlValue);
-
- if (updateConfigFile.Success)
- {
- return
- new HealthCheckStatus(_textService.Localize("healthcheck", "umbracoApplicationUrlConfigureSuccess", new[] { urlValue }))
- {
- ResultType = StatusResultType.Success
- };
- }
-
- return
- new HealthCheckStatus(_textService.Localize("healthcheck", "umbracoApplicationUrlConfigureError", new[] { updateConfigFile.Result }))
- {
- ResultType = StatusResultType.Error
- };
- }
- }
-}
diff --git a/templates/UmbracoExtension/README.txt b/templates/UmbracoExtension/README.txt
index 7beee9137e..e887480f11 100644
--- a/templates/UmbracoExtension/README.txt
+++ b/templates/UmbracoExtension/README.txt
@@ -35,4 +35,4 @@
* Use VSCode as the editor of choice as it has good tooling support for TypeScript and it will recommend a VSCode Extension for good Lit WebComponent completions
== Other Resources ==
-* Umbraco Docs - https://docs.umbraco.com/umbraco-cms/customizing/extend-and-customize-editing-experience
+* Umbraco Docs - https://docs.umbraco.com/umbraco-cms/customizing/overview
diff --git a/tests/Umbraco.Tests.Common/Builders/ContentTypeEditingBuilder.cs b/tests/Umbraco.Tests.Common/Builders/ContentTypeEditingBuilder.cs
index c9cdc41552..f34decd0c2 100644
--- a/tests/Umbraco.Tests.Common/Builders/ContentTypeEditingBuilder.cs
+++ b/tests/Umbraco.Tests.Common/Builders/ContentTypeEditingBuilder.cs
@@ -192,7 +192,7 @@ public class ContentTypeEditingBuilder : ContentTypeEditingBaseBuilder(),
loggerFactory.CreateLogger(),
Mock.Of(),
- Mock.Of(),
- Options.Create(new ContentSettings()));
+ Mock.Of());
var databaseFactory = new Mock();
var database = new Mock();
var sqlContext = new Mock();
@@ -207,7 +206,7 @@ public abstract class TestHelperBase
throw new ArgumentException("relativePath must start with '~/'", nameof(relativePath));
}
- var codeBase = typeof(TestHelperBase).Assembly.CodeBase;
+ var codeBase = typeof(TestHelperBase).Assembly.Location;
var uri = new Uri(codeBase);
var path = uri.LocalPath;
var bin = Path.GetDirectoryName(path);
diff --git a/tests/Umbraco.Tests.Common/TestLastChanceFinder.cs b/tests/Umbraco.Tests.Common/TestLastChanceFinder.cs
index 3b00e20981..85c8f7b97f 100644
--- a/tests/Umbraco.Tests.Common/TestLastChanceFinder.cs
+++ b/tests/Umbraco.Tests.Common/TestLastChanceFinder.cs
@@ -8,5 +8,5 @@ namespace Umbraco.Cms.Tests.Common;
public class TestLastChanceFinder : IContentLastChanceFinder
{
- public async Task TryFindContent(IPublishedRequestBuilder frequest) => false;
+ public Task TryFindContent(IPublishedRequestBuilder frequest) => Task.FromResult(false);
}