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); }