From 5e3bf194fd8d3dd99746994d11a0fa3602605c8d Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Fri, 14 Aug 2020 16:02:20 -0500 Subject: [PATCH 1/3] Use IPortalSettings in Localization APIs This is in preparation to move the Localization.SetThreadCultures call to an HttpModule. --- DNN Platform/Library/Framework/PageBase.cs | 15 ++-- .../Services/Localization/Localization.cs | 81 ++++++++++++------- .../DotNetNuke.Modules.CoreMessaging.csproj | 4 + .../Services/SubscriptionsController.cs | 14 ++-- 4 files changed, 72 insertions(+), 42 deletions(-) diff --git a/DNN Platform/Library/Framework/PageBase.cs b/DNN Platform/Library/Framework/PageBase.cs index ed24ed4a253..754672bc2bb 100644 --- a/DNN Platform/Library/Framework/PageBase.cs +++ b/DNN Platform/Library/Framework/PageBase.cs @@ -1,6 +1,6 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information namespace DotNetNuke.Framework { using System; @@ -13,7 +13,7 @@ namespace DotNetNuke.Framework using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; - + using DotNetNuke.Common; using DotNetNuke.Common.Utilities; using DotNetNuke.Entities.Host; @@ -25,8 +25,8 @@ namespace DotNetNuke.Framework using DotNetNuke.Services.Exceptions; using DotNetNuke.Services.Localization; using DotNetNuke.UI.Modules; - using DotNetNuke.Web.Client.ClientResourceManagement; - + using DotNetNuke.Web.Client.ClientResourceManagement; + /// ----------------------------------------------------------------------------- /// Namespace: DotNetNuke.Framework /// Project: DotNetNuke @@ -428,7 +428,8 @@ protected override void OnInit(EventArgs e) var isInstallPage = HttpContext.Current.Request.Url.LocalPath.ToLowerInvariant().Contains("installwizard.aspx"); if (!isInstallPage) { - Localization.SetThreadCultures(this.PageCulture, this.PortalSettings); + var portalSettings = PortalController.Instance.GetCurrentSettings(); + Localization.SetThreadCultures(Localization.GetPageLocale(portalSettings), portalSettings); } if (ScriptManager.GetCurrent(this) == null) diff --git a/DNN Platform/Library/Services/Localization/Localization.cs b/DNN Platform/Library/Services/Localization/Localization.cs index 3d84f9efb22..b162fedc5ce 100644 --- a/DNN Platform/Library/Services/Localization/Localization.cs +++ b/DNN Platform/Library/Services/Localization/Localization.cs @@ -1,33 +1,28 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information namespace DotNetNuke.Services.Localization { using System; using System.Collections; using System.Collections.Generic; - using System.Collections.Specialized; using System.Globalization; - using System.IO; using System.Linq; using System.Reflection; - using System.Text.RegularExpressions; using System.Threading; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; - using System.Xml; + using DotNetNuke.Abstractions.Portals; using DotNetNuke.Common; using DotNetNuke.Common.Utilities; using DotNetNuke.Data; - using DotNetNuke.Entities.Host; using DotNetNuke.Entities.Portals; using DotNetNuke.Entities.Tabs; using DotNetNuke.Entities.Users; using DotNetNuke.Instrumentation; using DotNetNuke.Security.Roles; - using DotNetNuke.Services.Cache; using DotNetNuke.Services.Localization.Internal; using DotNetNuke.Services.Log.EventLog; using DotNetNuke.Services.Tokens; @@ -41,8 +36,8 @@ namespace DotNetNuke.Services.Localization /// good support for international users. Otherwise we are limiting our potential user base to /// that using English as their base language. /// - /// You can store the muti language content in resource files and use the api below to get localization content. - /// Resouces files named as: Control(Page)Name + Extension (.aspx/.ascx ) + Language + ".resx" + /// You can store the multi language content in resource files and use the api below to get localization content. + /// Resources files named as: Control(Page)Name + Extension (.aspx/.ascx ) + Language + ".resx" /// e.g: Installwizard.aspx.de-DE.resx. /// /// @@ -576,7 +571,26 @@ public static string GetLocaleName(string code, CultureDropDownTypes displayType /// /// Current PortalSettings. /// A valid CultureInfo. + [Obsolete("Deprecated in Platform 9.8.0. Scheduled removal in v11.0.0. Use overload taking IPortalSettings instead.")] public static CultureInfo GetPageLocale(PortalSettings portalSettings) + { + return GetPageLocale((IPortalSettings)portalSettings); + } + + /// + /// Detects the current language for the request. + /// The order in which the language is being detect is: + /// 1. QueryString + /// 2. Cookie + /// 3. User profile (if request is authenticated) + /// 4. Browser preference (if portal has this option enabled) + /// 5. Portal default + /// 6. System default (en-US) + /// At any point, if a valid language is detected nothing else should be done. + /// + /// Current PortalSettings. + /// A valid CultureInfo. + public static CultureInfo GetPageLocale(IPortalSettings portalSettings) { CultureInfo pageCulture = null; @@ -1583,20 +1597,31 @@ public static void SetLanguage(string value) } } - /// - /// Sets the culture codes on the current Thread. - /// - /// Culture Info for the current page. - /// The current portalSettings. + /// Sets the culture codes on the current Thread. + /// Culture Info for the current page. + /// The current portal settings. /// - /// This method will configure the Thread culture codes. Any page which does not derive from PageBase should - /// be sure to call this method in OnInit to ensure localiztion works correctly. See the TelerikDialogHandler for an example. + /// This method will configure the Thread culture codes. Any page which does not derive from should + /// be sure to call this method in to ensure localization works correctly. See the for an example. /// + [Obsolete("Deprecated in Platform 9.8.0. Scheduled removal in v11.0.0. Use overload taking IPortalSettings instead.")] public static void SetThreadCultures(CultureInfo cultureInfo, PortalSettings portalSettings) + { + SetThreadCultures(cultureInfo, (IPortalSettings)portalSettings); + } + + /// Sets the culture codes on the current Thread. + /// Culture Info for the current page. + /// The current portal settings. + /// + /// This method will configure the Thread culture codes. Any page which does not derive from should + /// be sure to call this method in to ensure localization works correctly. See the for an example. + /// + public static void SetThreadCultures(CultureInfo cultureInfo, IPortalSettings portalSettings) { if (cultureInfo == null) { - throw new ArgumentNullException("cultureInfo"); + throw new ArgumentNullException(nameof(cultureInfo)); } if (cultureInfo.Name == "fa-IR") @@ -1895,7 +1920,7 @@ private static string GetValidLanguageURL(int portalId, string httpAlias, string /// /// Current PortalSettings. /// A valid CultureInfo if any is found. - private static CultureInfo GetCultureFromQs(PortalSettings portalSettings) + private static CultureInfo GetCultureFromQs(IPortalSettings portalSettings) { if (HttpContext.Current == null || HttpContext.Current.Request["language"] == null) { @@ -1912,7 +1937,7 @@ private static CultureInfo GetCultureFromQs(PortalSettings portalSettings) /// /// Current PortalSettings. /// A valid CultureInfo if any is found. - private static CultureInfo GetCultureFromCookie(PortalSettings portalSettings) + private static CultureInfo GetCultureFromCookie(IPortalSettings portalSettings) { CultureInfo culture; if (HttpContext.Current == null || HttpContext.Current.Request.Cookies["language"] == null) @@ -1930,7 +1955,7 @@ private static CultureInfo GetCultureFromCookie(PortalSettings portalSettings) /// /// Current PortalSettings. /// A valid CultureInfo if any is found. - private static CultureInfo GetCultureFromProfile(PortalSettings portalSettings) + private static CultureInfo GetCultureFromProfile(IPortalSettings portalSettings) { UserInfo objUserInfo = UserController.Instance.GetCurrentUserInfo(); @@ -1950,7 +1975,7 @@ private static CultureInfo GetCultureFromProfile(PortalSettings portalSettings) /// /// Current PortalSettings. /// A valid CultureInfo if any is found. - private static CultureInfo GetCultureFromBrowser(PortalSettings portalSettings) + private static CultureInfo GetCultureFromBrowser(IPortalSettings portalSettings) { if (!portalSettings.EnableBrowserLanguage) { @@ -1967,7 +1992,7 @@ private static CultureInfo GetCultureFromBrowser(PortalSettings portalSettings) /// /// Current PortalSettings. /// A valid CultureInfo if any is found. - private static CultureInfo GetCultureFromPortal(PortalSettings portalSettings) + private static CultureInfo GetCultureFromPortal(IPortalSettings portalSettings) { CultureInfo culture = null; if (!string.IsNullOrEmpty(portalSettings.DefaultLanguage)) @@ -2004,13 +2029,13 @@ private static IList GetPortalLocalizations(int portalID) /// /// When portal allows users to select their preferred UI language, this method - /// will return the user ui preferred language if defined. Otherwise defaults + /// will return the user UI preferred language if defined. Otherwise defaults /// to the current culture. /// /// Current culture. - /// PortalSettings for the current request. - /// - private static CultureInfo GetUserUICulture(CultureInfo currentCulture, PortalSettings portalSettings) + /// Portal settings for the current request. + /// A instance representing the user's UI culture. + private static CultureInfo GetUserUICulture(CultureInfo currentCulture, IPortalSettings portalSettings) { CultureInfo uiCulture = currentCulture; try diff --git a/DNN Platform/Modules/CoreMessaging/DotNetNuke.Modules.CoreMessaging.csproj b/DNN Platform/Modules/CoreMessaging/DotNetNuke.Modules.CoreMessaging.csproj index 8c3d10a9623..831572f1f4a 100644 --- a/DNN Platform/Modules/CoreMessaging/DotNetNuke.Modules.CoreMessaging.csproj +++ b/DNN Platform/Modules/CoreMessaging/DotNetNuke.Modules.CoreMessaging.csproj @@ -167,6 +167,10 @@ + + {6928a9b1-f88a-4581-a132-d3eb38669bb0} + DotNetNuke.Abstractions + {ee1329fe-fd88-4e1a-968c-345e394ef080} DotNetNuke.Web diff --git a/DNN Platform/Modules/CoreMessaging/Services/SubscriptionsController.cs b/DNN Platform/Modules/CoreMessaging/Services/SubscriptionsController.cs index 44c0f81d714..b0b0e6e07d5 100644 --- a/DNN Platform/Modules/CoreMessaging/Services/SubscriptionsController.cs +++ b/DNN Platform/Modules/CoreMessaging/Services/SubscriptionsController.cs @@ -1,7 +1,6 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information - +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information namespace DotNetNuke.Modules.CoreMessaging.Services { using System; @@ -13,7 +12,8 @@ namespace DotNetNuke.Modules.CoreMessaging.Services using System.Net.Http; using System.Web.Http; using System.Xml; - + + using DotNetNuke.Abstractions.Portals; using DotNetNuke.Entities.Modules; using DotNetNuke.Modules.CoreMessaging.ViewModels; using DotNetNuke.Services.Exceptions; @@ -22,7 +22,7 @@ namespace DotNetNuke.Modules.CoreMessaging.Services using DotNetNuke.Services.Social.Subscriptions; using DotNetNuke.Services.Social.Subscriptions.Entities; using DotNetNuke.Web.Api; - + [DnnAuthorize] public class SubscriptionsController : DnnApiController { @@ -154,7 +154,7 @@ public HttpResponseMessage GetLocalizationTable(string culture) { if (!string.IsNullOrEmpty(culture)) { - Localization.SetThreadCultures(new CultureInfo(culture), this.PortalSettings); + Localization.SetThreadCultures(new CultureInfo(culture), (IPortalSettings)this.PortalSettings); } var dictionary = new Dictionary(); From e5364f148746137371af8b70121253f07e360b8c Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Fri, 14 Aug 2020 16:06:23 -0500 Subject: [PATCH 2/3] Move Localization.SetThreadCultures to HttpModule This is in support of turning on Async for Default.aspx. Per a discussion with the ASP.NET team, setting the thread culture in OnInit for a page does not persist in the context for the page (once Async is turned on an there are multiple contexts to consider). Setting it from an IHttpModule implementation, however, will persist throughout that request. This fixes the bug that plagued #2089, where, as an example, URLs would be generated for the incorrect language once Async was on. --- .../HttpModules/DotNetNuke.HttpModules.csproj | 1 + .../Localization/LocalizationModule.cs | 39 +++++++++++++++++++ DNN Platform/Library/Framework/PageBase.cs | 6 --- .../Website/Install/Config/09.08.00.config | 7 ++++ DNN Platform/Website/development.config | 1 + DNN Platform/Website/release.config | 1 + 6 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 DNN Platform/HttpModules/Localization/LocalizationModule.cs create mode 100644 DNN Platform/Website/Install/Config/09.08.00.config diff --git a/DNN Platform/HttpModules/DotNetNuke.HttpModules.csproj b/DNN Platform/HttpModules/DotNetNuke.HttpModules.csproj index c9b9ec652a3..c61b606a527 100644 --- a/DNN Platform/HttpModules/DotNetNuke.HttpModules.csproj +++ b/DNN Platform/HttpModules/DotNetNuke.HttpModules.csproj @@ -72,6 +72,7 @@ SolutionInfo.cs + diff --git a/DNN Platform/HttpModules/Localization/LocalizationModule.cs b/DNN Platform/HttpModules/Localization/LocalizationModule.cs new file mode 100644 index 00000000000..e7e5b3ec3f9 --- /dev/null +++ b/DNN Platform/HttpModules/Localization/LocalizationModule.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.HttpModules.Localization +{ + using System; + using System.Web; + + using DotNetNuke.Entities.Portals; + using DotNetNuke.Services.Localization; + + /// Sets up localization for all requests. + public class LocalizationModule : IHttpModule + { + /// + public void Init(HttpApplication context) + { + context.BeginRequest += Context_BeginRequest; + } + + /// + public void Dispose() + { + // intentionally left empty + } + + private static void Context_BeginRequest(object sender, EventArgs e) + { + var isInstallPage = HttpContext.Current.Request.Url.LocalPath.ToLowerInvariant().Contains("installwizard.aspx"); + if (isInstallPage) + { + return; + } + + var portalSettings = PortalController.Instance.GetCurrentSettings(); + Localization.SetThreadCultures(Localization.GetPageLocale(portalSettings), portalSettings); + } + } +} diff --git a/DNN Platform/Library/Framework/PageBase.cs b/DNN Platform/Library/Framework/PageBase.cs index 754672bc2bb..d78da905f0e 100644 --- a/DNN Platform/Library/Framework/PageBase.cs +++ b/DNN Platform/Library/Framework/PageBase.cs @@ -426,12 +426,6 @@ protected override void OnError(EventArgs e) protected override void OnInit(EventArgs e) { var isInstallPage = HttpContext.Current.Request.Url.LocalPath.ToLowerInvariant().Contains("installwizard.aspx"); - if (!isInstallPage) - { - var portalSettings = PortalController.Instance.GetCurrentSettings(); - Localization.SetThreadCultures(Localization.GetPageLocale(portalSettings), portalSettings); - } - if (ScriptManager.GetCurrent(this) == null) { AJAX.AddScriptManager(this, !isInstallPage); diff --git a/DNN Platform/Website/Install/Config/09.08.00.config b/DNN Platform/Website/Install/Config/09.08.00.config new file mode 100644 index 00000000000..f3d65c1555f --- /dev/null +++ b/DNN Platform/Website/Install/Config/09.08.00.config @@ -0,0 +1,7 @@ + + + + + + + diff --git a/DNN Platform/Website/development.config b/DNN Platform/Website/development.config index e845aac347c..b1d2f0065b1 100644 --- a/DNN Platform/Website/development.config +++ b/DNN Platform/Website/development.config @@ -82,6 +82,7 @@ + diff --git a/DNN Platform/Website/release.config b/DNN Platform/Website/release.config index b0ebb33f3a6..45cb2be1891 100644 --- a/DNN Platform/Website/release.config +++ b/DNN Platform/Website/release.config @@ -82,6 +82,7 @@ + From b41843104ac15385dbab0ca79cfcc01f48f6a1ec Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Fri, 14 Aug 2020 16:09:51 -0500 Subject: [PATCH 3/3] Add Async support to Default.aspx This is a second try for 0cf1b13b2f076b6f7314142c1778ca97c267ba0b #2089. This will allow for async calls from WebForms controls (preferably via calling RegisterAsyncTask, see https://docs.microsoft.com/en-us/aspnet/web-forms/overview/performance-and-caching/using-asynchronous-methods-in-aspnet-45#registerasynctask-notes) --- DNN Platform/Website/Default.aspx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DNN Platform/Website/Default.aspx b/DNN Platform/Website/Default.aspx index 655dab9d599..55831a5879f 100644 --- a/DNN Platform/Website/Default.aspx +++ b/DNN Platform/Website/Default.aspx @@ -1,4 +1,4 @@ -<%@ Page Language="C#" AutoEventWireup="True" Inherits="DotNetNuke.Framework.DefaultPage" CodeBehind="Default.aspx.cs" %> +<%@ Page Language="C#" AutoEventWireup="True" Inherits="DotNetNuke.Framework.DefaultPage" CodeBehind="Default.aspx.cs" Async="true" %> <%@ Register TagPrefix="dnncrm" Namespace="DotNetNuke.Web.Client.ClientResourceManagement" Assembly="DotNetNuke.Web.Client" %> <%@ Register TagPrefix="dnn" Namespace="DotNetNuke.Common.Controls" Assembly="DotNetNuke" %> @@ -12,14 +12,14 @@ - + - +