diff --git a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs index 20630a7249..8008253db4 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs @@ -13,6 +13,7 @@ using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Tests.PublishedContent; using Umbraco.Tests.TestHelpers.Stubs; +using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web.Routing; namespace Umbraco.Tests.TestHelpers @@ -83,7 +84,8 @@ namespace Umbraco.Tests.TestHelpers return new PublishedRouter( webRoutingSection, contentFinders ?? new ContentFinderCollection(Enumerable.Empty()), - new TestLastChanceFinder(), + new TestLastChanceFinder(), + new TestVariationContextAccessor(), container?.TryGetInstance() ?? new ServiceContext(), new ProfilingLogger(Mock.Of(), Mock.Of())); } diff --git a/src/Umbraco.Web/Models/PublishedContent/HttpContextVariationContextAccessor.cs b/src/Umbraco.Web/Models/PublishedContent/HttpContextVariationContextAccessor.cs new file mode 100644 index 0000000000..70672e3796 --- /dev/null +++ b/src/Umbraco.Web/Models/PublishedContent/HttpContextVariationContextAccessor.cs @@ -0,0 +1,28 @@ +using Umbraco.Core.Models.PublishedContent; + +namespace Umbraco.Web.Models.PublishedContent +{ + /// + /// Implements on top of . + /// + public class HttpContextVariationContextAccessor : IVariationContextAccessor + { + public const string ContextKey = "Umbraco.Web.Models.PublishedContent.DefaultVariationContextAccessor"; + public readonly IHttpContextAccessor HttpContextAccessor; + + /// + /// Initializes a new instance of the class. + /// + public HttpContextVariationContextAccessor(IHttpContextAccessor httpContextAccessor) + { + HttpContextAccessor = httpContextAccessor; + } + + /// + public VariationContext VariationContext + { + get => (VariationContext) HttpContextAccessor.HttpContext.Items[ContextKey]; + set => HttpContextAccessor.HttpContext.Items[ContextKey] = value; + } + } +} diff --git a/src/Umbraco.Web/Routing/PublishedRouter.cs b/src/Umbraco.Web/Routing/PublishedRouter.cs index 3d712f3abb..fdc8540aa0 100644 --- a/src/Umbraco.Web/Routing/PublishedRouter.cs +++ b/src/Umbraco.Web/Routing/PublishedRouter.cs @@ -27,6 +27,7 @@ namespace Umbraco.Web.Routing private readonly IContentLastChanceFinder _contentLastChanceFinder; private readonly ServiceContext _services; private readonly ProfilingLogger _profilingLogger; + private readonly IVariationContextAccessor _variationContextAccessor; private readonly ILogger _logger; /// @@ -36,6 +37,7 @@ namespace Umbraco.Web.Routing IWebRoutingSection webRoutingSection, ContentFinderCollection contentFinders, IContentLastChanceFinder contentLastChanceFinder, + IVariationContextAccessor variationContextAccessor, ServiceContext services, ProfilingLogger proflog, Func> getRolesForLogin = null) @@ -45,6 +47,7 @@ namespace Umbraco.Web.Routing _contentLastChanceFinder = contentLastChanceFinder ?? throw new ArgumentNullException(nameof(contentLastChanceFinder)); _services = services ?? throw new ArgumentNullException(nameof(services)); _profilingLogger = proflog ?? throw new ArgumentNullException(nameof(proflog)); + _variationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor)); _logger = proflog.Logger; GetRolesForLogin = getRolesForLogin ?? (s => Roles.Provider.GetRolesForUser(s)); @@ -89,6 +92,13 @@ namespace Umbraco.Web.Routing return request.HasPublishedContent; } + private void SetVariationContext(string culture) + { + var variationContext = _variationContextAccessor.VariationContext; + if (variationContext != null && variationContext.Culture == culture) return; + _variationContextAccessor.VariationContext = new VariationContext(culture); + } + /// /// Prepares the request. /// @@ -123,6 +133,7 @@ namespace Umbraco.Web.Routing // set the culture on the thread - once, so it's set when running document lookups Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = request.Culture; + SetVariationContext(request.Culture.Name); //find the published content if it's not assigned. This could be manually assigned with a custom route handler, or // with something like EnsurePublishedContentRequestAttribute or UmbracoVirtualNodeRouteHandler. Those in turn call this method @@ -138,6 +149,7 @@ namespace Umbraco.Web.Routing // set the culture on the thread -- again, 'cos it might have changed due to a finder or wildcard domain Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = request.Culture; + SetVariationContext(request.Culture.Name); // trigger the Prepared event - at that point it is still possible to change about anything // even though the request might be flagged for redirection - we'll redirect _after_ the event @@ -173,6 +185,7 @@ namespace Umbraco.Web.Routing // set the culture on the thread -- again, 'cos it might have changed in the event handler Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = frequest.Culture; + SetVariationContext(frequest.Culture.Name); // if request has been flagged to redirect, or has no content to display, // then return - whoever called us is in charge of actually redirecting diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs index 6b9109b7df..a4e5db0767 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs @@ -72,7 +72,7 @@ namespace Umbraco.Web.Runtime // register accessors for cultures composition.Container.RegisterSingleton(); - composition.Container.RegisterSingleton(); + composition.Container.RegisterSingleton(); var typeLoader = composition.Container.GetInstance(); var logger = composition.Container.GetInstance(); diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index b0dc6b7a8b..f9708e5c04 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -252,6 +252,7 @@ +