Ensures the culture is set for requests for both front-end and back office
This commit is contained in:
@@ -123,10 +123,6 @@ namespace Umbraco.Web.Routing
|
||||
|
||||
private void SetVariationContext(CultureInfo culture)
|
||||
{
|
||||
// set the culture on the thread - once, so it's set when running document lookups
|
||||
// TODO: Set this on HttpContext!
|
||||
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = culture;
|
||||
|
||||
VariationContext variationContext = _variationContextAccessor.VariationContext;
|
||||
if (variationContext != null && variationContext.Culture == culture?.Name)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
@@ -35,8 +35,6 @@ namespace Umbraco.Tests.Routing
|
||||
null, // FIXME: PublishedRouter complexities...
|
||||
Mock.Of<IUmbracoContextFactory>(),
|
||||
new RoutableDocumentFilter(globalSettings, IOHelper),
|
||||
UriUtility,
|
||||
AppCaches.RequestCache,
|
||||
globalSettings,
|
||||
HostingEnvironment
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.ViewEngines;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Web.Common.ActionsResults;
|
||||
@@ -70,12 +71,13 @@ namespace Umbraco.Web.Common.Controllers
|
||||
return _umbracoRouteValues;
|
||||
}
|
||||
|
||||
if (!ControllerContext.RouteData.Values.TryGetValue(Core.Constants.Web.UmbracoRouteDefinitionDataToken, out var def))
|
||||
_umbracoRouteValues = HttpContext.GetRouteValue(Core.Constants.Web.UmbracoRouteDefinitionDataToken) as UmbracoRouteValues;
|
||||
|
||||
if (_umbracoRouteValues == null)
|
||||
{
|
||||
throw new InvalidOperationException($"No route value found with key {Core.Constants.Web.UmbracoRouteDefinitionDataToken}");
|
||||
}
|
||||
|
||||
_umbracoRouteValues = (UmbracoRouteValues)def;
|
||||
return _umbracoRouteValues;
|
||||
}
|
||||
}
|
||||
@@ -126,10 +128,10 @@ namespace Umbraco.Web.Common.Controllers
|
||||
IPublishedRequest pcr = UmbracoRouteValues.PublishedRequest;
|
||||
|
||||
_logger.LogDebug(
|
||||
"Response status: Redirect={Redirect}, Is404={Is404}, StatusCode={ResponseStatusCode}",
|
||||
pcr.IsRedirect() ? (pcr.IsRedirectPermanent() ? "permanent" : "redirect") : "none",
|
||||
pcr.Is404() ? "true" : "false",
|
||||
pcr.ResponseStatusCode);
|
||||
"Response status: Content={Content}, StatusCode={ResponseStatusCode}, Culture={Culture}",
|
||||
pcr.PublishedContent?.Id ?? -1,
|
||||
pcr.ResponseStatusCode,
|
||||
pcr.Culture);
|
||||
|
||||
UmbracoRouteResult routeStatus = pcr.GetRouteResult();
|
||||
switch (routeStatus)
|
||||
|
||||
@@ -48,9 +48,11 @@ using Umbraco.Web.Common.Controllers;
|
||||
using Umbraco.Web.Common.DependencyInjection;
|
||||
using Umbraco.Web.Common.Install;
|
||||
using Umbraco.Web.Common.Lifetime;
|
||||
using Umbraco.Web.Common.Localization;
|
||||
using Umbraco.Web.Common.Macros;
|
||||
using Umbraco.Web.Common.Middleware;
|
||||
using Umbraco.Web.Common.ModelBinders;
|
||||
using Umbraco.Web.Common.Mvc;
|
||||
using Umbraco.Web.Common.Profiler;
|
||||
using Umbraco.Web.Common.Routing;
|
||||
using Umbraco.Web.Common.Security;
|
||||
@@ -226,6 +228,7 @@ namespace Umbraco.Web.Common.DependencyInjection
|
||||
});
|
||||
|
||||
builder.Services.ConfigureOptions<UmbracoMvcConfigureOptions>();
|
||||
builder.Services.ConfigureOptions<UmbracoRequestLocalizationOptions>();
|
||||
builder.Services.TryAddEnumerable(ServiceDescriptor.Transient<IApplicationModelProvider, UmbracoApiBehaviorApplicationModelProvider>());
|
||||
builder.Services.TryAddEnumerable(ServiceDescriptor.Transient<IApplicationModelProvider, BackOfficeApplicationModelProvider>());
|
||||
builder.Services.AddUmbracoImageSharp(builder.Config);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Serilog.Context;
|
||||
@@ -57,9 +58,10 @@ namespace Umbraco.Extensions
|
||||
// where we need to have UseAuthentication and UseAuthorization proceeding this call but before
|
||||
// endpoints are defined.
|
||||
app.UseRouting();
|
||||
app.UseRequestLocalization();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
// This must come after auth because the culture is based on the auth'd user
|
||||
app.UseRequestLocalization();
|
||||
|
||||
// Must be called after UseRouting and before UseEndpoints
|
||||
app.UseSession();
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
using Umbraco.Core.Security;
|
||||
|
||||
namespace Umbraco.Web.Common.Extensions
|
||||
namespace Umbraco.Web.Common.Localization
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Sets the request culture to the culture of the back office user if one is determined to be in the request
|
||||
/// </summary>
|
||||
public class UmbracoBackOfficeIdentityCultureProvider : RequestCultureProvider
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
|
||||
{
|
||||
var culture = httpContext.User.Identity.GetCulture();
|
||||
CultureInfo culture = httpContext.User.Identity.GetCulture();
|
||||
|
||||
if (culture is null)
|
||||
{
|
||||
return NullProviderCultureResult;
|
||||
}
|
||||
|
||||
return Task.FromResult(new ProviderCultureResult(culture.Name, culture.Name));
|
||||
return Task.FromResult(new ProviderCultureResult(culture.Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Umbraco.Web.Common.Routing;
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Web.Common.Localization
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the request culture to the culture of the <see cref="IPublishedRequest"/> if one is found in the request
|
||||
/// </summary>
|
||||
public class UmbracoPublishedContentCultureProvider : RequestCultureProvider
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
|
||||
{
|
||||
if (httpContext.GetRouteValue(Core.Constants.Web.UmbracoRouteDefinitionDataToken) is UmbracoRouteValues routeValues)
|
||||
{
|
||||
CultureInfo culture = routeValues.PublishedRequest?.Culture;
|
||||
if (culture != null)
|
||||
{
|
||||
return Task.FromResult(new ProviderCultureResult(culture.Name));
|
||||
}
|
||||
}
|
||||
|
||||
return NullProviderCultureResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Core.Configuration.Models;
|
||||
|
||||
namespace Umbraco.Web.Common.Localization
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom Umbraco options configuration for <see cref="RequestLocalizationOptions"/>
|
||||
/// </summary>
|
||||
public class UmbracoRequestLocalizationOptions : IConfigureOptions<RequestLocalizationOptions>
|
||||
{
|
||||
private readonly IOptions<GlobalSettings> _globalSettings;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UmbracoRequestLocalizationOptions"/> class.
|
||||
/// </summary>
|
||||
public UmbracoRequestLocalizationOptions(IOptions<GlobalSettings> globalSettings) => _globalSettings = globalSettings;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Configure(RequestLocalizationOptions options)
|
||||
{
|
||||
// set the default culture to what is in config
|
||||
options.DefaultRequestCulture = new RequestCulture(_globalSettings.Value.DefaultUILanguage);
|
||||
|
||||
// add a custom provider
|
||||
if (options.RequestCultureProviders == null)
|
||||
{
|
||||
options.RequestCultureProviders = new List<IRequestCultureProvider>();
|
||||
}
|
||||
|
||||
options.RequestCultureProviders.Insert(0, new UmbracoBackOfficeIdentityCultureProvider());
|
||||
options.RequestCultureProviders.Insert(1, new UmbracoPublishedContentCultureProvider());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,9 @@ using Microsoft.Extensions.Options;
|
||||
using Umbraco.Web.Common.Filters;
|
||||
using Umbraco.Web.Common.ModelBinders;
|
||||
|
||||
namespace Umbraco.Web.Common.AspNetCore
|
||||
namespace Umbraco.Web.Common.Mvc
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Options for globally configuring MVC for Umbraco
|
||||
/// </summary>
|
||||
@@ -37,10 +37,8 @@ namespace Umbraco.Web
|
||||
private readonly IPublishedRouter _publishedRouter;
|
||||
private readonly IUmbracoContextFactory _umbracoContextFactory;
|
||||
private readonly RoutableDocumentFilter _routableDocumentLookup;
|
||||
private readonly IRequestCache _requestCache;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IHostingEnvironment _hostingEnvironment;
|
||||
private readonly UriUtility _uriUtility;
|
||||
|
||||
public UmbracoInjectedModule(
|
||||
IRuntimeState runtime,
|
||||
@@ -48,8 +46,6 @@ namespace Umbraco.Web
|
||||
IPublishedRouter publishedRouter,
|
||||
IUmbracoContextFactory umbracoContextFactory,
|
||||
RoutableDocumentFilter routableDocumentLookup,
|
||||
UriUtility uriUtility,
|
||||
IRequestCache requestCache,
|
||||
GlobalSettings globalSettings,
|
||||
IHostingEnvironment hostingEnvironment)
|
||||
{
|
||||
@@ -58,8 +54,6 @@ namespace Umbraco.Web
|
||||
_publishedRouter = publishedRouter;
|
||||
_umbracoContextFactory = umbracoContextFactory;
|
||||
_routableDocumentLookup = routableDocumentLookup;
|
||||
_uriUtility = uriUtility;
|
||||
_requestCache = requestCache;
|
||||
_globalSettings = globalSettings;
|
||||
_hostingEnvironment = hostingEnvironment;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user