diff --git a/src/OrchardCore.Modules/OrchardCore.Email.Azure/Drivers/AzureEmailSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Email.Azure/Drivers/AzureEmailSettingsDisplayDriver.cs index 84a6dc23acb..038fe75e55d 100644 --- a/src/OrchardCore.Modules/OrchardCore.Email.Azure/Drivers/AzureEmailSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Email.Azure/Drivers/AzureEmailSettingsDisplayDriver.cs @@ -24,29 +24,26 @@ namespace OrchardCore.Azure.Email.Drivers; public class AzureEmailSettingsDisplayDriver : SectionDisplayDriver { + private readonly IShellReleaseManager _shellReleaseManager; private readonly IHttpContextAccessor _httpContextAccessor; private readonly IAuthorizationService _authorizationService; private readonly IDataProtectionProvider _dataProtectionProvider; - private readonly IShellHost _shellHost; - private readonly ShellSettings _shellSettings; private readonly IEmailAddressValidator _emailValidator; protected IStringLocalizer S; public AzureEmailSettingsDisplayDriver( + IShellReleaseManager shellReleaseManager, IHttpContextAccessor httpContextAccessor, IAuthorizationService authorizationService, IDataProtectionProvider dataProtectionProvider, - IShellHost shellHost, - ShellSettings shellSettings, IEmailAddressValidator emailValidator, IStringLocalizer stringLocalizer) { + _shellReleaseManager = shellReleaseManager; _httpContextAccessor = httpContextAccessor; _authorizationService = authorizationService; _dataProtectionProvider = dataProtectionProvider; - _shellHost = shellHost; - _shellSettings = shellSettings; _emailValidator = emailValidator; S = stringLocalizer; } @@ -150,8 +147,7 @@ public override async Task UpdateAsync(ISite site, AzureEmailSet if (hasChanges) { - // Release the tenant to apply the settings when something changed. - await _shellHost.ReleaseShellContextAsync(_shellSettings); + _shellReleaseManager.RequestRelease(); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Email.Smtp/Drivers/SmtpSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Email.Smtp/Drivers/SmtpSettingsDisplayDriver.cs index 4c006df36f3..d0104ff289d 100644 --- a/src/OrchardCore.Modules/OrchardCore.Email.Smtp/Drivers/SmtpSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Email.Smtp/Drivers/SmtpSettingsDisplayDriver.cs @@ -25,9 +25,8 @@ public class SmtpSettingsDisplayDriver : SectionDisplayDriver options, IAuthorizationService authorizationService, IEmailAddressValidator emailAddressValidator, IStringLocalizer stringLocalizer) { + _shellReleaseManager = shellReleaseManager; _dataProtectionProvider = dataProtectionProvider; - _shellHost = shellHost; - _shellSettings = shellSettings; _httpContextAccessor = httpContextAccessor; _smtpOptions = options.Value; _authorizationService = authorizationService; @@ -200,8 +197,7 @@ public override async Task UpdateAsync(ISite site, SmtpSettings if (hasChanges) { - // Release the tenant to apply the settings when something changed. - await _shellHost.ReleaseShellContextAsync(_shellSettings); + _shellReleaseManager.RequestRelease(); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Email/Drivers/EmailSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Email/Drivers/EmailSettingsDisplayDriver.cs index 77d135ece9e..23805558783 100644 --- a/src/OrchardCore.Modules/OrchardCore.Email/Drivers/EmailSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Email/Drivers/EmailSettingsDisplayDriver.cs @@ -22,10 +22,9 @@ public class EmailSettingsDisplayDriver : SectionDisplayDriver emailProviders, IOptions emailOptions, IEmailProviderResolver emailProviderResolver, - ShellSettings shellSettings, + IShellReleaseManager shellReleaseManager, IStringLocalizer stringLocalizer) { _httpContextAccessor = httpContextAccessor; _authorizationService = authorizationService; - _shellHost = shellHost; _emailOptions = emailOptions.Value; _emailProviderResolver = emailProviderResolver; _emailProviders = emailProviders.Value; - _shellSettings = shellSettings; + _shellReleaseManager = shellReleaseManager; S = stringLocalizer; } public override async Task EditAsync(EmailSettings settings, BuildEditorContext context) @@ -91,7 +88,7 @@ public override async Task UpdateAsync(EmailSettings settings, U { settings.DefaultProviderName = model.DefaultProvider; - await _shellHost.ReleaseShellContextAsync(_shellSettings); + _shellReleaseManager.RequestRelease(); } return await EditAsync(settings, context); diff --git a/src/OrchardCore.Modules/OrchardCore.Facebook/Drivers/FacebookSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Facebook/Drivers/FacebookSettingsDisplayDriver.cs index 27bb5179b09..e3a4f0ccbcb 100644 --- a/src/OrchardCore.Modules/OrchardCore.Facebook/Drivers/FacebookSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Facebook/Drivers/FacebookSettingsDisplayDriver.cs @@ -16,27 +16,24 @@ namespace OrchardCore.Facebook.Drivers { public class FacebookSettingsDisplayDriver : SectionDisplayDriver { + private readonly IShellReleaseManager _shellReleaseManager; private readonly IAuthorizationService _authorizationService; private readonly IDataProtectionProvider _dataProtectionProvider; private readonly IHttpContextAccessor _httpContextAccessor; - private readonly IShellHost _shellHost; - private readonly ShellSettings _shellSettings; private readonly ILogger _logger; public FacebookSettingsDisplayDriver( + IShellReleaseManager shellReleaseManager, IAuthorizationService authorizationService, IDataProtectionProvider dataProtectionProvider, IHttpContextAccessor httpContextAccessor, - IShellHost shellHost, - ShellSettings shellSettings, ILogger logger ) { + _shellReleaseManager = shellReleaseManager; _authorizationService = authorizationService; _dataProtectionProvider = dataProtectionProvider; _httpContextAccessor = httpContextAccessor; - _shellHost = shellHost; - _shellSettings = shellSettings; _logger = logger; } @@ -87,19 +84,23 @@ public override async Task UpdateAsync(FacebookSettings settings var model = new FacebookSettingsViewModel(); await context.Updater.TryUpdateModelAsync(model, Prefix); + settings.AppId = model.AppId; + settings.FBInit = model.FBInit; + settings.SdkJs = model.SdkJs; + settings.Version = model.Version; + + if (!string.IsNullOrWhiteSpace(model.FBInitParams)) + { + settings.FBInitParams = model.FBInitParams; + } + if (context.Updater.ModelState.IsValid) { var protector = _dataProtectionProvider.CreateProtector(FacebookConstants.Features.Core); - settings.AppId = model.AppId; settings.AppSecret = protector.Protect(model.AppSecret); - settings.FBInit = model.FBInit; - settings.SdkJs = model.SdkJs; - if (!string.IsNullOrWhiteSpace(model.FBInitParams)) - settings.FBInitParams = model.FBInitParams; - settings.Version = model.Version; - - await _shellHost.ReleaseShellContextAsync(_shellSettings); } + + _shellReleaseManager.RequestRelease(); } return await EditAsync(settings, context); diff --git a/src/OrchardCore.Modules/OrchardCore.Facebook/Login/Drivers/FacebookLoginSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Facebook/Login/Drivers/FacebookLoginSettingsDisplayDriver.cs index 7b2a019424f..d3d7de29eac 100644 --- a/src/OrchardCore.Modules/OrchardCore.Facebook/Login/Drivers/FacebookLoginSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Facebook/Login/Drivers/FacebookLoginSettingsDisplayDriver.cs @@ -13,21 +13,18 @@ namespace OrchardCore.Facebook.Login.Drivers { public class FacebookLoginSettingsDisplayDriver : SectionDisplayDriver { + private readonly IShellReleaseManager _shellReleaseManager; private readonly IAuthorizationService _authorizationService; private readonly IHttpContextAccessor _httpContextAccessor; - private readonly IShellHost _shellHost; - private readonly ShellSettings _shellSettings; public FacebookLoginSettingsDisplayDriver( + IShellReleaseManager shellReleaseManager, IAuthorizationService authorizationService, - IHttpContextAccessor httpContextAccessor, - IShellHost shellHost, - ShellSettings shellSettings) + IHttpContextAccessor httpContextAccessor) { + _shellReleaseManager = shellReleaseManager; _authorizationService = authorizationService; _httpContextAccessor = httpContextAccessor; - _shellHost = shellHost; - _shellSettings = shellSettings; } public override async Task EditAsync(FacebookLoginSettings settings, BuildEditorContext context) @@ -56,15 +53,15 @@ public override async Task UpdateAsync(FacebookLoginSettings set } var model = new FacebookLoginSettingsViewModel(); + await context.Updater.TryUpdateModelAsync(model, Prefix); - if (context.Updater.ModelState.IsValid) - { - settings.CallbackPath = model.CallbackPath; - settings.SaveTokens = model.SaveTokens; - await _shellHost.ReleaseShellContextAsync(_shellSettings); - } + settings.CallbackPath = model.CallbackPath; + settings.SaveTokens = model.SaveTokens; + + _shellReleaseManager.RequestRelease(); } + return await EditAsync(settings, context); } } diff --git a/src/OrchardCore.Modules/OrchardCore.GitHub/Drivers/GithubAuthenticationSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.GitHub/Drivers/GithubAuthenticationSettingsDisplayDriver.cs index 611b3d3b8ad..1b39f9c4742 100644 --- a/src/OrchardCore.Modules/OrchardCore.GitHub/Drivers/GithubAuthenticationSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.GitHub/Drivers/GithubAuthenticationSettingsDisplayDriver.cs @@ -16,26 +16,23 @@ namespace OrchardCore.GitHub.Drivers { public class GitHubAuthenticationSettingsDisplayDriver : SectionDisplayDriver { + private readonly IShellReleaseManager _shellReleaseManager; private readonly IAuthorizationService _authorizationService; private readonly IDataProtectionProvider _dataProtectionProvider; private readonly IHttpContextAccessor _httpContextAccessor; - private readonly IShellHost _shellHost; - private readonly ShellSettings _shellSettings; private readonly ILogger _logger; public GitHubAuthenticationSettingsDisplayDriver( + IShellReleaseManager shellReleaseManager, IAuthorizationService authorizationService, IDataProtectionProvider dataProtectionProvider, IHttpContextAccessor httpContextAccessor, - IShellHost shellHost, - ShellSettings shellSettings, ILogger logger) { + _shellReleaseManager = shellReleaseManager; _authorizationService = authorizationService; _dataProtectionProvider = dataProtectionProvider; _httpContextAccessor = httpContextAccessor; - _shellHost = shellHost; - _shellSettings = shellSettings; _logger = logger; } @@ -97,9 +94,11 @@ public override async Task UpdateAsync(GitHubAuthenticationSetti settings.ClientSecret = protector.Protect(model.ClientSecret); settings.CallbackPath = model.CallbackUrl; settings.SaveTokens = model.SaveTokens; - await _shellHost.ReleaseShellContextAsync(_shellSettings); + + _shellReleaseManager.RequestRelease(); } } + return await EditAsync(settings, context); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Google/Authentication/Drivers/GoogleAuthenticationSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Google/Authentication/Drivers/GoogleAuthenticationSettingsDisplayDriver.cs index e55a70d373d..2557cfb5bae 100644 --- a/src/OrchardCore.Modules/OrchardCore.Google/Authentication/Drivers/GoogleAuthenticationSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Google/Authentication/Drivers/GoogleAuthenticationSettingsDisplayDriver.cs @@ -16,26 +16,23 @@ namespace OrchardCore.Google.Authentication.Drivers { public class GoogleAuthenticationSettingsDisplayDriver : SectionDisplayDriver { + private readonly IShellReleaseManager _shellReleaseManager; private readonly IAuthorizationService _authorizationService; private readonly IDataProtectionProvider _dataProtectionProvider; private readonly IHttpContextAccessor _httpContextAccessor; - private readonly IShellHost _shellHost; - private readonly ShellSettings _shellSettings; private readonly ILogger _logger; public GoogleAuthenticationSettingsDisplayDriver( + IShellReleaseManager shellReleaseManager, IAuthorizationService authorizationService, IDataProtectionProvider dataProtectionProvider, IHttpContextAccessor httpContextAccessor, - IShellHost shellHost, - ShellSettings shellSettings, ILogger logger) { + _shellReleaseManager = shellReleaseManager; _authorizationService = authorizationService; _dataProtectionProvider = dataProtectionProvider; _httpContextAccessor = httpContextAccessor; - _shellHost = shellHost; - _shellSettings = shellSettings; _logger = logger; } @@ -89,17 +86,20 @@ public override async Task UpdateAsync(GoogleAuthenticationSetti var model = new GoogleAuthenticationSettingsViewModel(); await context.Updater.TryUpdateModelAsync(model, Prefix); + settings.ClientID = model.ClientID; + settings.CallbackPath = model.CallbackPath; + settings.SaveTokens = model.SaveTokens; + if (context.Updater.ModelState.IsValid) { var protector = _dataProtectionProvider.CreateProtector(GoogleConstants.Features.GoogleAuthentication); - settings.ClientID = model.ClientID; settings.ClientSecret = protector.Protect(model.ClientSecret); - settings.CallbackPath = model.CallbackPath; - settings.SaveTokens = model.SaveTokens; - await _shellHost.ReleaseShellContextAsync(_shellSettings); } + + _shellReleaseManager.RequestRelease(); } + return await EditAsync(settings, context); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Https/Drivers/HttpsSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Https/Drivers/HttpsSettingsDisplayDriver.cs index c58e42bb141..1d926262a4a 100644 --- a/src/OrchardCore.Modules/OrchardCore.Https/Drivers/HttpsSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Https/Drivers/HttpsSettingsDisplayDriver.cs @@ -19,25 +19,24 @@ public class HttpsSettingsDisplayDriver : SectionDisplayDriver htmlLocalizer) { + _shellReleaseManager = shellReleaseManager; _httpContextAccessor = httpContextAccessor; _authorizationService = authorizationService; _notifier = notifier; - _shellHost = shellHost; - _shellSettings = shellSettings; H = htmlLocalizer; } @@ -94,11 +93,7 @@ public override async Task UpdateAsync(HttpsSettings settings, U settings.RequireHttpsPermanent = model.RequireHttpsPermanent; settings.SslPort = model.SslPort; - // If the settings are valid, release the current tenant. - if (context.Updater.ModelState.IsValid) - { - await _shellHost.ReleaseShellContextAsync(_shellSettings); - } + _shellReleaseManager.RequestRelease(); } return await EditAsync(settings, context); diff --git a/src/OrchardCore.Modules/OrchardCore.Layers/Drivers/LayerSiteSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Layers/Drivers/LayerSiteSettingsDisplayDriver.cs index 49bade39027..56bcbe13c30 100644 --- a/src/OrchardCore.Modules/OrchardCore.Layers/Drivers/LayerSiteSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Layers/Drivers/LayerSiteSettingsDisplayDriver.cs @@ -14,9 +14,10 @@ namespace OrchardCore.Layers.Drivers public class LayerSiteSettingsDisplayDriver : SectionDisplayDriver { public const string GroupId = "zones"; + private static readonly char[] _separator = [' ', ',']; + private readonly IHttpContextAccessor _httpContextAccessor; private readonly IAuthorizationService _authorizationService; - private static readonly char[] _separator = [' ', ',']; public LayerSiteSettingsDisplayDriver( IHttpContextAccessor httpContextAccessor, diff --git a/src/OrchardCore.Modules/OrchardCore.Localization/Drivers/LocalizationSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Localization/Drivers/LocalizationSettingsDisplayDriver.cs index dec0c6d6575..2bf5b95a455 100644 --- a/src/OrchardCore.Modules/OrchardCore.Localization/Drivers/LocalizationSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Localization/Drivers/LocalizationSettingsDisplayDriver.cs @@ -25,10 +25,8 @@ namespace OrchardCore.Localization.Drivers public class LocalizationSettingsDisplayDriver : SectionDisplayDriver { public const string GroupId = "localization"; - + private readonly IShellReleaseManager _shellReleaseManager; private readonly INotifier _notifier; - private readonly IShellHost _shellHost; - private readonly ShellSettings _shellSettings; private readonly IHttpContextAccessor _httpContextAccessor; private readonly IAuthorizationService _authorizationService; private readonly CultureOptions _cultureOptions; @@ -37,9 +35,8 @@ public class LocalizationSettingsDisplayDriver : SectionDisplayDriver cultureOptions, @@ -47,9 +44,8 @@ public LocalizationSettingsDisplayDriver( IStringLocalizer stringLocalizer ) { + _shellReleaseManager = shellReleaseManager; _notifier = notifier; - _shellHost = shellHost; - _shellSettings = shellSettings; _httpContextAccessor = httpContextAccessor; _authorizationService = authorizationService; _cultureOptions = cultureOptions.Value; @@ -95,7 +91,7 @@ public override async Task EditAsync(LocalizationSettings settin } /// - public override async Task UpdateAsync(LocalizationSettings section, UpdateEditorContext context) + public override async Task UpdateAsync(LocalizationSettings settings, UpdateEditorContext context) { var user = _httpContextAccessor.HttpContext?.User; @@ -119,26 +115,26 @@ public override async Task UpdateAsync(LocalizationSettings sect if (context.Updater.ModelState.IsValid) { // Invariant culture name is empty so a null value is bound. - section.DefaultCulture = model.DefaultCulture ?? ""; - section.SupportedCultures = supportedCulture; + settings.DefaultCulture = model.DefaultCulture ?? string.Empty; + settings.SupportedCultures = supportedCulture; - if (!section.SupportedCultures.Contains(section.DefaultCulture)) + if (!settings.SupportedCultures.Contains(settings.DefaultCulture)) { - section.DefaultCulture = section.SupportedCultures[0]; + settings.DefaultCulture = settings.SupportedCultures[0]; } // We always release the tenant for the default culture and also supported cultures to take effect. - await _shellHost.ReleaseShellContextAsync(_shellSettings); + _shellReleaseManager.RequestRelease(); // We create a transient scope with the newly selected culture to create a notification that will use it instead of the previous culture. - using (CultureScope.Create(section.DefaultCulture, ignoreSystemSettings: _cultureOptions.IgnoreSystemSettings)) + using (CultureScope.Create(settings.DefaultCulture, ignoreSystemSettings: _cultureOptions.IgnoreSystemSettings)) { await _notifier.WarningAsync(H["The site has been restarted for the settings to take effect."]); } } } - return await EditAsync(section, context); + return await EditAsync(settings, context); } } } diff --git a/src/OrchardCore.Modules/OrchardCore.Microsoft.Authentication/Drivers/AzureADSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Microsoft.Authentication/Drivers/AzureADSettingsDisplayDriver.cs index 0c4476ff957..af11f55998f 100644 --- a/src/OrchardCore.Modules/OrchardCore.Microsoft.Authentication/Drivers/AzureADSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Microsoft.Authentication/Drivers/AzureADSettingsDisplayDriver.cs @@ -13,21 +13,18 @@ namespace OrchardCore.Microsoft.Authentication.Drivers { public class AzureADSettingsDisplayDriver : SectionDisplayDriver { + private readonly IShellReleaseManager _shellReleaseManager; private readonly IAuthorizationService _authorizationService; private readonly IHttpContextAccessor _httpContextAccessor; - private readonly IShellHost _shellHost; - private readonly ShellSettings _shellSettings; public AzureADSettingsDisplayDriver( + IShellReleaseManager shellReleaseManager, IAuthorizationService authorizationService, - IHttpContextAccessor httpContextAccessor, - IShellHost shellHost, - ShellSettings shellSettings) + IHttpContextAccessor httpContextAccessor) { + _shellReleaseManager = shellReleaseManager; _authorizationService = authorizationService; _httpContextAccessor = httpContextAccessor; - _shellHost = shellHost; - _shellSettings = shellSettings; } public override async Task EditAsync(AzureADSettings settings, BuildEditorContext context) @@ -59,18 +56,20 @@ public override async Task UpdateAsync(AzureADSettings settings, { return null; } + var model = new AzureADSettingsViewModel(); + await context.Updater.TryUpdateModelAsync(model, Prefix); - if (context.Updater.ModelState.IsValid) - { - settings.DisplayName = model.DisplayName; - settings.AppId = model.AppId; - settings.TenantId = model.TenantId; - settings.CallbackPath = model.CallbackPath; - settings.SaveTokens = model.SaveTokens; - await _shellHost.ReleaseShellContextAsync(_shellSettings); - } + + settings.DisplayName = model.DisplayName; + settings.AppId = model.AppId; + settings.TenantId = model.TenantId; + settings.CallbackPath = model.CallbackPath; + settings.SaveTokens = model.SaveTokens; + + _shellReleaseManager.RequestRelease(); } + return await EditAsync(settings, context); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Microsoft.Authentication/Drivers/MicrosoftAccountSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Microsoft.Authentication/Drivers/MicrosoftAccountSettingsDisplayDriver.cs index ea78b820391..18a3fd8eda8 100644 --- a/src/OrchardCore.Modules/OrchardCore.Microsoft.Authentication/Drivers/MicrosoftAccountSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Microsoft.Authentication/Drivers/MicrosoftAccountSettingsDisplayDriver.cs @@ -16,26 +16,23 @@ namespace OrchardCore.Microsoft.Authentication.Drivers { public class MicrosoftAccountSettingsDisplayDriver : SectionDisplayDriver { + private readonly IShellReleaseManager _shellReleaseManager; private readonly IAuthorizationService _authorizationService; private readonly IDataProtectionProvider _dataProtectionProvider; private readonly IHttpContextAccessor _httpContextAccessor; - private readonly IShellHost _shellHost; - private readonly ShellSettings _shellSettings; private readonly ILogger _logger; public MicrosoftAccountSettingsDisplayDriver( + IShellReleaseManager shellReleaseManager, IAuthorizationService authorizationService, IDataProtectionProvider dataProtectionProvider, IHttpContextAccessor httpContextAccessor, - IShellHost shellHost, - ShellSettings shellSettings, ILogger logger) { + _shellReleaseManager = shellReleaseManager; _authorizationService = authorizationService; _dataProtectionProvider = dataProtectionProvider; _httpContextAccessor = httpContextAccessor; - _shellHost = shellHost; - _shellSettings = shellSettings; _logger = logger; } @@ -89,17 +86,20 @@ public override async Task UpdateAsync(MicrosoftAccountSettings var model = new MicrosoftAccountSettingsViewModel(); await context.Updater.TryUpdateModelAsync(model, Prefix); + settings.AppId = model.AppId; + settings.CallbackPath = model.CallbackPath; + settings.SaveTokens = model.SaveTokens; + if (context.Updater.ModelState.IsValid) { var protector = _dataProtectionProvider.CreateProtector(MicrosoftAuthenticationConstants.Features.MicrosoftAccount); - settings.AppId = model.AppId; settings.AppSecret = protector.Protect(model.AppSecret); - settings.CallbackPath = model.CallbackPath; - settings.SaveTokens = model.SaveTokens; - await _shellHost.ReleaseShellContextAsync(_shellSettings); } + + _shellReleaseManager.RequestRelease(); } + return await EditAsync(settings, context); } } diff --git a/src/OrchardCore.Modules/OrchardCore.OpenId/Drivers/OpenIdClientSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.OpenId/Drivers/OpenIdClientSettingsDisplayDriver.cs index 14a66304c54..d725514d47a 100644 --- a/src/OrchardCore.Modules/OrchardCore.OpenId/Drivers/OpenIdClientSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.OpenId/Drivers/OpenIdClientSettingsDisplayDriver.cs @@ -26,29 +26,27 @@ public class OpenIdClientSettingsDisplayDriver : SectionDisplayDriver stringLocalizer) { + _shellReleaseManager = shellReleaseManager; _authorizationService = authorizationService; _dataProtectionProvider = dataProtectionProvider; _clientService = clientService; _httpContextAccessor = httpContextAccessor; - _shellHost = shellHost; - _shellSettings = shellSettings; S = stringLocalizer; } @@ -205,11 +203,7 @@ public override async Task UpdateAsync(OpenIdClientSettings sett } } - // If the settings are valid, release the current tenant. - if (context.Updater.ModelState.IsValid) - { - await _shellHost.ReleaseShellContextAsync(_shellSettings); - } + _shellReleaseManager.RequestRelease(); } return await EditAsync(settings, context); diff --git a/src/OrchardCore.Modules/OrchardCore.ReCaptcha/Drivers/ReCaptchaSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.ReCaptcha/Drivers/ReCaptchaSettingsDisplayDriver.cs index 62bbaec4cba..3283fcb2fa4 100644 --- a/src/OrchardCore.Modules/OrchardCore.ReCaptcha/Drivers/ReCaptchaSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.ReCaptcha/Drivers/ReCaptchaSettingsDisplayDriver.cs @@ -16,19 +16,17 @@ namespace OrchardCore.ReCaptcha.Drivers public class ReCaptchaSettingsDisplayDriver : SectionDisplayDriver { public const string GroupId = "recaptcha"; - private readonly IShellHost _shellHost; - private readonly ShellSettings _shellSettings; + + private readonly IShellReleaseManager _shellReleaseManager; private readonly IHttpContextAccessor _httpContextAccessor; private readonly IAuthorizationService _authorizationService; public ReCaptchaSettingsDisplayDriver( - IShellHost shellHost, - ShellSettings shellSettings, + IShellReleaseManager shellReleaseManager, IHttpContextAccessor httpContextAccessor, IAuthorizationService authorizationService) { - _shellHost = shellHost; - _shellSettings = shellSettings; + _shellReleaseManager = shellReleaseManager; _httpContextAccessor = httpContextAccessor; _authorizationService = authorizationService; } @@ -58,7 +56,7 @@ public override async Task EditAsync(ReCaptchaSettings settings, .OnGroup(GroupId); } - public override async Task UpdateAsync(ReCaptchaSettings section, UpdateEditorContext context) + public override async Task UpdateAsync(ReCaptchaSettings settings, UpdateEditorContext context) { var user = _httpContextAccessor.HttpContext?.User; @@ -73,14 +71,13 @@ public override async Task UpdateAsync(ReCaptchaSettings section await context.Updater.TryUpdateModelAsync(model, Prefix); - section.SiteKey = model.SiteKey?.Trim(); - section.SecretKey = model.SecretKey?.Trim(); + settings.SiteKey = model.SiteKey?.Trim(); + settings.SecretKey = model.SecretKey?.Trim(); - // Release the tenant to apply settings. - await _shellHost.ReleaseShellContextAsync(_shellSettings); + _shellReleaseManager.RequestRelease(); } - return await EditAsync(section, context); + return await EditAsync(settings, context); } } } diff --git a/src/OrchardCore.Modules/OrchardCore.ReverseProxy/Drivers/ReverseProxySettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.ReverseProxy/Drivers/ReverseProxySettingsDisplayDriver.cs index 517f26a2ccd..2984b90fed6 100644 --- a/src/OrchardCore.Modules/OrchardCore.ReverseProxy/Drivers/ReverseProxySettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.ReverseProxy/Drivers/ReverseProxySettingsDisplayDriver.cs @@ -18,19 +18,16 @@ public class ReverseProxySettingsDisplayDriver : SectionDisplayDriver EditAsync(ReverseProxySettings settin .OnGroup(GroupId); } - public override async Task UpdateAsync(ReverseProxySettings section, UpdateEditorContext context) + public override async Task UpdateAsync(ReverseProxySettings settings, UpdateEditorContext context) { var user = _httpContextAccessor.HttpContext?.User; @@ -75,25 +72,27 @@ public override async Task UpdateAsync(ReverseProxySettings sect await context.Updater.TryUpdateModelAsync(model, Prefix); - section.ForwardedHeaders = ForwardedHeaders.None; + settings.ForwardedHeaders = ForwardedHeaders.None; if (model.EnableXForwardedFor) - section.ForwardedHeaders |= ForwardedHeaders.XForwardedFor; + { + settings.ForwardedHeaders |= ForwardedHeaders.XForwardedFor; + } if (model.EnableXForwardedHost) - section.ForwardedHeaders |= ForwardedHeaders.XForwardedHost; + { + settings.ForwardedHeaders |= ForwardedHeaders.XForwardedHost; + } if (model.EnableXForwardedProto) - section.ForwardedHeaders |= ForwardedHeaders.XForwardedProto; - - // If the settings are valid, release the current tenant. - if (context.Updater.ModelState.IsValid) { - await _shellHost.ReleaseShellContextAsync(_shellSettings); + settings.ForwardedHeaders |= ForwardedHeaders.XForwardedProto; } + + _shellReleaseManager.RequestRelease(); } - return await EditAsync(section, context); + return await EditAsync(settings, context); } } } diff --git a/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Drivers/AzureAISearchDefaultSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Drivers/AzureAISearchDefaultSettingsDisplayDriver.cs index 07bd71badcd..fe6b8a6068d 100644 --- a/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Drivers/AzureAISearchDefaultSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Drivers/AzureAISearchDefaultSettingsDisplayDriver.cs @@ -23,34 +23,26 @@ public class AzureAISearchDefaultSettingsDisplayDriver : SectionDisplayDriver searchOptions, - ShellSettings shellSettings, - IShellHost shellHost, IDataProtectionProvider dataProtectionProvider, IStringLocalizer stringLocalizer ) { - _indexSettingsService = indexSettingsService; + _shellReleaseManager = shellReleaseManager; _httpContextAccessor = httpContextAccessor; _authorizationService = authorizationService; - _shellSettings = shellSettings; - _shellHost = shellHost; _searchOptions = searchOptions.Value; _dataProtectionProvider = dataProtectionProvider; S = stringLocalizer; @@ -65,12 +57,12 @@ public override IDisplayResult Edit(AzureAISearchDefaultSettings settings) return Initialize("AzureAISearchDefaultSettings_Edit", model => { - model.AuthenticationTypes = new[] - { + model.AuthenticationTypes = + [ new SelectListItem(S["Default"], nameof(AzureAIAuthenticationType.Default)), new SelectListItem(S["Managed Identity"], nameof(AzureAIAuthenticationType.ManagedIdentity)), new SelectListItem(S["API Key"], nameof(AzureAIAuthenticationType.ApiKey)), - }; + ]; model.ConfigurationsAreOptional = _searchOptions.FileConfigurationExists(); model.AuthenticationType = settings.AuthenticationType; @@ -141,13 +133,13 @@ public override async Task UpdateAsync(AzureAISearchDefaultSetti settings.UseCustomConfiguration = model.UseCustomConfiguration; if (context.Updater.ModelState.IsValid && - (_searchOptions.Credential?.Key != model.ApiKey - || _searchOptions.Endpoint != settings.Endpoint - || _searchOptions.AuthenticationType != settings.AuthenticationType - || _searchOptions.IdentityClientId != settings.IdentityClientId - || useCustomConfigurationChanged)) + (_searchOptions.Credential?.Key != model.ApiKey || + _searchOptions.Endpoint != settings.Endpoint || + _searchOptions.AuthenticationType != settings.AuthenticationType || + _searchOptions.IdentityClientId != settings.IdentityClientId || + useCustomConfigurationChanged)) { - await _shellHost.ReleaseShellContextAsync(_shellSettings); + _shellReleaseManager.RequestRelease(); } return Edit(settings); diff --git a/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Drivers/AzureAISearchSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Drivers/AzureAISearchSettingsDisplayDriver.cs index 0a7589b675a..66f2658a957 100644 --- a/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Drivers/AzureAISearchSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Drivers/AzureAISearchSettingsDisplayDriver.cs @@ -25,24 +25,22 @@ public class AzureAISearchSettingsDisplayDriver : SectionDisplayDriver stringLocalizer ) { _indexSettingsService = indexSettingsService; _httpContextAccessor = httpContextAccessor; _authorizationService = authorizationService; - _shellHost = shellHost; - _shellSettings = shellSettings; + _shellReleaseManager = shellReleaseManager; S = stringLocalizer; } @@ -58,7 +56,7 @@ public override IDisplayResult Edit(AzureAISearchSettings settings) .RenderWhen(() => _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext.User, AzureAISearchIndexPermissionHelper.ManageAzureAISearchIndexes)) .OnGroup(SearchConstants.SearchSettingsGroupId); - public override async Task UpdateAsync(AzureAISearchSettings section, UpdateEditorContext context) + public override async Task UpdateAsync(AzureAISearchSettings settings, UpdateEditorContext context) { if (!SearchConstants.SearchSettingsGroupId.EqualsOrdinalIgnoreCase(context.GroupId)) { @@ -91,18 +89,15 @@ public override async Task UpdateAsync(AzureAISearchSettings sec var fields = model.SearchFields?.Split(_separator, StringSplitOptions.RemoveEmptyEntries); - if (section.SearchIndex != model.SearchIndex || !AreTheSame(section.DefaultSearchFields, fields)) + if (settings.SearchIndex != model.SearchIndex || !AreTheSame(settings.DefaultSearchFields, fields)) { - section.SearchIndex = model.SearchIndex; - section.DefaultSearchFields = fields; + settings.SearchIndex = model.SearchIndex; + settings.DefaultSearchFields = fields; - if (context.Updater.ModelState.IsValid) - { - await _shellHost.ReleaseShellContextAsync(_shellSettings); - } + _shellReleaseManager.RequestRelease(); } - return Edit(section); + return Edit(settings); } private static bool AreTheSame(string[] a, string[] b) diff --git a/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/Drivers/ElasticSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/Drivers/ElasticSettingsDisplayDriver.cs index c266e70ccd9..14a34941d30 100644 --- a/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/Drivers/ElasticSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/Drivers/ElasticSettingsDisplayDriver.cs @@ -26,11 +26,6 @@ public class ElasticSettingsDisplayDriver : SectionDisplayDriver securitySettings) { - _shellHost = shellHost; - _shellSettings = shellSettings; + _shellReleaseManager = shellReleaseManager; _httpContextAccessor = httpContextAccessor; _authorizationService = authorizationService; _securitySettings = securitySettings.Value; @@ -77,7 +74,7 @@ public override async Task EditAsync(SecuritySettings settings, }).Location("Content:2").OnGroup(SettingsGroupId); } - public override async Task UpdateAsync(SecuritySettings section, UpdateEditorContext context) + public override async Task UpdateAsync(SecuritySettings settings, UpdateEditorContext context) { var user = _httpContextAccessor.HttpContext?.User; @@ -94,18 +91,15 @@ public override async Task UpdateAsync(SecuritySettings section, PrepareContentSecurityPolicyValues(model); - section.ContentTypeOptions = SecurityHeaderDefaults.ContentTypeOptions; - section.ContentSecurityPolicy = model.ContentSecurityPolicy; - section.PermissionsPolicy = model.PermissionsPolicy; - section.ReferrerPolicy = model.ReferrerPolicy; + settings.ContentTypeOptions = SecurityHeaderDefaults.ContentTypeOptions; + settings.ContentSecurityPolicy = model.ContentSecurityPolicy; + settings.PermissionsPolicy = model.PermissionsPolicy; + settings.ReferrerPolicy = model.ReferrerPolicy; - if (context.Updater.ModelState.IsValid) - { - await _shellHost.ReleaseShellContextAsync(_shellSettings); - } + _shellReleaseManager.RequestRelease(); } - return await EditAsync(section, context); + return await EditAsync(settings, context); } private static void PrepareContentSecurityPolicyValues(SecuritySettingsViewModel model) diff --git a/src/OrchardCore.Modules/OrchardCore.Seo/Drivers/RobotsSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Seo/Drivers/RobotsSettingsDisplayDriver.cs index c8baf40e490..f2e395fe038 100644 --- a/src/OrchardCore.Modules/OrchardCore.Seo/Drivers/RobotsSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Seo/Drivers/RobotsSettingsDisplayDriver.cs @@ -18,6 +18,7 @@ public class RobotsSettingsDisplayDriver : SectionDisplayDriver _siteSettingsDisplayManager; + private readonly IShellReleaseManager _shellReleaseManager; private readonly ISiteService _siteService; private readonly INotifier _notifier; private readonly IAuthorizationService _authorizationService; private readonly IUpdateModelAccessor _updateModelAccessor; private readonly CultureOptions _cultureOptions; + protected readonly IHtmlLocalizer H; public AdminController( + IShellReleaseManager shellReleaseManager, ISiteService siteService, IDisplayManager siteSettingsDisplayManager, IAuthorizationService authorizationService, INotifier notifier, - IHtmlLocalizer h, IOptions cultureOptions, - IUpdateModelAccessor updateModelAccessor) + IUpdateModelAccessor updateModelAccessor, + IHtmlLocalizer htmlLocalizer) { _siteSettingsDisplayManager = siteSettingsDisplayManager; + _shellReleaseManager = shellReleaseManager; _siteService = siteService; _notifier = notifier; _authorizationService = authorizationService; _updateModelAccessor = updateModelAccessor; _cultureOptions = cultureOptions.Value; - H = h; + H = htmlLocalizer; } [Admin("Settings/{groupId}", "AdminSettings")] @@ -54,7 +59,7 @@ public async Task Index(string groupId) var viewModel = new AdminIndexViewModel { GroupId = groupId, - Shape = await _siteSettingsDisplayManager.BuildEditorAsync(site, _updateModelAccessor.ModelUpdater, false, groupId, "") + Shape = await _siteSettingsDisplayManager.BuildEditorAsync(site, _updateModelAccessor.ModelUpdater, false, groupId, string.Empty) }; return View(viewModel); @@ -74,7 +79,7 @@ public async Task IndexPost(string groupId) var viewModel = new AdminIndexViewModel { GroupId = groupId, - Shape = await _siteSettingsDisplayManager.UpdateEditorAsync(site, _updateModelAccessor.ModelUpdater, false, groupId, "") + Shape = await _siteSettingsDisplayManager.UpdateEditorAsync(site, _updateModelAccessor.ModelUpdater, false, groupId, string.Empty) }; if (ModelState.IsValid) @@ -95,6 +100,11 @@ public async Task IndexPost(string groupId) return RedirectToAction(nameof(Index), new { groupId }); } + else + { + // If the model state is invalid, suspend the request to release the shell so that the tenant is not reloaded. + _shellReleaseManager.SuspendReleaseRequest(); + } return View(viewModel); } diff --git a/src/OrchardCore.Modules/OrchardCore.Settings/Drivers/DefaultSiteSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Settings/Drivers/DefaultSiteSettingsDisplayDriver.cs index 634cbf46c69..a3cffba89db 100644 --- a/src/OrchardCore.Modules/OrchardCore.Settings/Drivers/DefaultSiteSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Settings/Drivers/DefaultSiteSettingsDisplayDriver.cs @@ -13,18 +13,15 @@ public class DefaultSiteSettingsDisplayDriver : DisplayDriver { public const string GroupId = "general"; - protected readonly IStringLocalizer S; + private readonly IShellReleaseManager _shellReleaseManager; - private readonly IShellHost _shellHost; - private readonly ShellSettings _shellSettings; + protected readonly IStringLocalizer S; public DefaultSiteSettingsDisplayDriver( - IShellHost shellHost, - ShellSettings shellSettings, + IShellReleaseManager shellReleaseManager, IStringLocalizer stringLocalizer) { - _shellHost = shellHost; - _shellSettings = shellSettings; + _shellReleaseManager = shellReleaseManager; S = stringLocalizer; } @@ -89,10 +86,7 @@ public override async Task UpdateAsync(ISite site, UpdateEditorC context.Updater.ModelState.AddModelError(Prefix, nameof(model.BaseUrl), S["The Base url must be a fully qualified URL."]); } - if (context.Updater.ModelState.IsValid) - { - await _shellHost.ReleaseShellContextAsync(_shellSettings); - } + _shellReleaseManager.RequestRelease(); return await EditAsync(site, context); } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms/Drivers/SmsSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Sms/Drivers/SmsSettingsDisplayDriver.cs index 387546125bd..eab91deff2d 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms/Drivers/SmsSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms/Drivers/SmsSettingsDisplayDriver.cs @@ -19,28 +19,25 @@ namespace OrchardCore.Sms.Drivers; public class SmsSettingsDisplayDriver : SectionDisplayDriver { + private readonly IShellReleaseManager _shellReleaseManager; private readonly IHttpContextAccessor _httpContextAccessor; private readonly IAuthorizationService _authorizationService; - private readonly IShellHost _shellHost; - private readonly ShellSettings _shellSettings; protected IStringLocalizer S; private readonly SmsProviderOptions _smsProviderOptions; public SmsSettingsDisplayDriver( + IShellReleaseManager shellReleaseManager, IHttpContextAccessor httpContextAccessor, IAuthorizationService authorizationService, - IShellHost shellHost, IOptions smsProviders, - ShellSettings shellSettings, IStringLocalizer stringLocalizer) { + _shellReleaseManager = shellReleaseManager; _httpContextAccessor = httpContextAccessor; _authorizationService = authorizationService; - _shellHost = shellHost; _smsProviderOptions = smsProviders.Value; - _shellSettings = shellSettings; S = stringLocalizer; } @@ -82,7 +79,7 @@ public override async Task UpdateAsync(SmsSettings settings, Upd { settings.DefaultProviderName = model.DefaultProvider; - await _shellHost.ReleaseShellContextAsync(_shellSettings); + _shellReleaseManager.RequestRelease(); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms/Drivers/TwilioSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Sms/Drivers/TwilioSettingsDisplayDriver.cs index 35cc4082bab..cf7a018cfa1 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms/Drivers/TwilioSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms/Drivers/TwilioSettingsDisplayDriver.cs @@ -23,34 +23,31 @@ namespace OrchardCore.Sms.Drivers; public class TwilioSettingsDisplayDriver : SectionDisplayDriver { + private readonly IShellReleaseManager _shellReleaseManager; private readonly IHttpContextAccessor _httpContextAccessor; private readonly IAuthorizationService _authorizationService; private readonly IPhoneFormatValidator _phoneFormatValidator; private readonly IDataProtectionProvider _dataProtectionProvider; - private readonly IShellHost _shellHost; - private readonly ShellSettings _shellSettings; private readonly INotifier _notifier; protected readonly IHtmlLocalizer H; protected readonly IStringLocalizer S; public TwilioSettingsDisplayDriver( + IShellReleaseManager shellReleaseManager, IHttpContextAccessor httpContextAccessor, IAuthorizationService authorizationService, IPhoneFormatValidator phoneFormatValidator, IDataProtectionProvider dataProtectionProvider, - IShellHost shellHost, - ShellSettings shellSettings, INotifier notifier, IHtmlLocalizer htmlLocalizer, IStringLocalizer stringLocalizer) { + _shellReleaseManager = shellReleaseManager; _httpContextAccessor = httpContextAccessor; _authorizationService = authorizationService; _phoneFormatValidator = phoneFormatValidator; _dataProtectionProvider = dataProtectionProvider; - _shellHost = shellHost; - _shellSettings = shellSettings; _notifier = notifier; H = htmlLocalizer; S = stringLocalizer; @@ -140,9 +137,9 @@ public override async Task UpdateAsync(ISite site, TwilioSetting } } - if (context.Updater.ModelState.IsValid && hasChanges) + if (hasChanges) { - await _shellHost.ReleaseShellContextAsync(_shellSettings); + _shellReleaseManager.RequestRelease(); } return Edit(settings); diff --git a/src/OrchardCore.Modules/OrchardCore.Twitter/Drivers/TwitterSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Twitter/Drivers/TwitterSettingsDisplayDriver.cs index bb768c59d54..5754a343734 100644 --- a/src/OrchardCore.Modules/OrchardCore.Twitter/Drivers/TwitterSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Twitter/Drivers/TwitterSettingsDisplayDriver.cs @@ -16,26 +16,23 @@ namespace OrchardCore.Twitter.Drivers { public class TwitterSettingsDisplayDriver : SectionDisplayDriver { + private readonly IShellReleaseManager _shellReleaseManager; private readonly IAuthorizationService _authorizationService; private readonly IDataProtectionProvider _dataProtectionProvider; private readonly IHttpContextAccessor _httpContextAccessor; - private readonly IShellHost _shellHost; - private readonly ShellSettings _shellSettings; private readonly ILogger _logger; public TwitterSettingsDisplayDriver( + IShellReleaseManager shellReleaseManager, IAuthorizationService authorizationService, IDataProtectionProvider dataProtectionProvider, IHttpContextAccessor httpContextAccessor, - IShellHost shellHost, - ShellSettings shellSettings, ILogger logger) { + _shellReleaseManager = shellReleaseManager; _authorizationService = authorizationService; _dataProtectionProvider = dataProtectionProvider; _httpContextAccessor = httpContextAccessor; - _shellHost = shellHost; - _shellSettings = shellSettings; _logger = logger; } @@ -104,17 +101,20 @@ public override async Task UpdateAsync(TwitterSettings settings, var model = new TwitterSettingsViewModel(); await context.Updater.TryUpdateModelAsync(model, Prefix); + settings.ConsumerKey = model.APIKey; + settings.AccessToken = model.AccessToken; + if (context.Updater.ModelState.IsValid) { var protector = _dataProtectionProvider.CreateProtector(TwitterConstants.Features.Twitter); - settings.ConsumerKey = model.APIKey; settings.ConsumerSecret = protector.Protect(model.APISecretKey); - settings.AccessToken = model.AccessToken; settings.AccessTokenSecret = protector.Protect(model.AccessTokenSecret); - await _shellHost.ReleaseShellContextAsync(_shellSettings); } + + _shellReleaseManager.RequestRelease(); } + return await EditAsync(settings, context); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Twitter/Signin/Drivers/TwitterSigninSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Twitter/Signin/Drivers/TwitterSigninSettingsDisplayDriver.cs index 467b16bf3c0..e3331541314 100644 --- a/src/OrchardCore.Modules/OrchardCore.Twitter/Signin/Drivers/TwitterSigninSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Twitter/Signin/Drivers/TwitterSigninSettingsDisplayDriver.cs @@ -13,21 +13,18 @@ namespace OrchardCore.Twitter.Signin.Drivers { public class TwitterSigninSettingsDisplayDriver : SectionDisplayDriver { + private readonly IShellReleaseManager _shellReleaseManager; private readonly IAuthorizationService _authorizationService; private readonly IHttpContextAccessor _httpContextAccessor; - private readonly IShellHost _shellHost; - private readonly ShellSettings _shellSettings; public TwitterSigninSettingsDisplayDriver( + IShellReleaseManager shellReleaseManager, IAuthorizationService authorizationService, - IHttpContextAccessor httpContextAccessor, - IShellHost shellHost, - ShellSettings shellSettings) + IHttpContextAccessor httpContextAccessor) { + _shellReleaseManager = shellReleaseManager; _authorizationService = authorizationService; _httpContextAccessor = httpContextAccessor; - _shellHost = shellHost; - _shellSettings = shellSettings; } public override async Task EditAsync(TwitterSigninSettings settings, BuildEditorContext context) @@ -47,7 +44,6 @@ public override async Task EditAsync(TwitterSigninSettings setti model.SaveTokens = settings.SaveTokens; }).Location("Content:5").OnGroup(TwitterConstants.Features.Signin); } - public override async Task UpdateAsync(TwitterSigninSettings settings, UpdateEditorContext context) { if (context.GroupId == TwitterConstants.Features.Signin) @@ -61,13 +57,12 @@ public override async Task UpdateAsync(TwitterSigninSettings set var model = new TwitterSigninSettingsViewModel(); await context.Updater.TryUpdateModelAsync(model, Prefix); - if (context.Updater.ModelState.IsValid) - { - settings.CallbackPath = model.CallbackPath; - settings.SaveTokens = model.SaveTokens; - await _shellHost.ReleaseShellContextAsync(_shellSettings); - } + settings.CallbackPath = model.CallbackPath; + settings.SaveTokens = model.SaveTokens; + + _shellReleaseManager.RequestRelease(); } + return await EditAsync(settings, context); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Drivers/RegistrationSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Users/Drivers/RegistrationSettingsDisplayDriver.cs index a585df302ee..64c71abfd92 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Drivers/RegistrationSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Drivers/RegistrationSettingsDisplayDriver.cs @@ -15,6 +15,7 @@ namespace OrchardCore.Users.Drivers public class RegistrationSettingsDisplayDriver : SectionDisplayDriver { public const string GroupId = "userRegistration"; + private readonly IHttpContextAccessor _httpContextAccessor; private readonly IAuthorizationService _authorizationService; diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Drivers/ResetPasswordSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Users/Drivers/ResetPasswordSettingsDisplayDriver.cs index 6e857b5c467..59e7e19e664 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Drivers/ResetPasswordSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Drivers/ResetPasswordSettingsDisplayDriver.cs @@ -15,6 +15,7 @@ namespace OrchardCore.Users.Drivers public class ResetPasswordSettingsDisplayDriver : SectionDisplayDriver { public const string GroupId = "userResetPassword"; + private readonly IHttpContextAccessor _httpContextAccessor; private readonly IAuthorizationService _authorizationService; diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Drivers/RoleLoginSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Users/Drivers/RoleLoginSettingsDisplayDriver.cs index e2bd80e9991..03c506f6d80 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Drivers/RoleLoginSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Drivers/RoleLoginSettingsDisplayDriver.cs @@ -21,6 +21,7 @@ public class RoleLoginSettingsDisplayDriver : SectionDisplayDriver + /// Adds a pending request to release the shell upon completion of the current HTTP-request. + /// + void RequestRelease(); + + /// + /// It suspends the pending release request to ensure that the shell remains intact when 'ProcessAsync()' is invoked. + /// + void SuspendReleaseRequest(); +} diff --git a/src/OrchardCore/OrchardCore.Abstractions/Shell/Scope/ShellScope.cs b/src/OrchardCore/OrchardCore.Abstractions/Shell/Scope/ShellScope.cs index df79c757eea..a5b7263a322 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Shell/Scope/ShellScope.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Shell/Scope/ShellScope.cs @@ -430,7 +430,7 @@ internal async Task BeforeDisposeAsync() scope = new ShellScope(ShellContext); } - // Use 'UsingAsync' in place of 'UsingServiceScopeAsync()' to allow a deferred task to + // Use 'UsingAsync()' in place of 'UsingServiceScopeAsync()' to allow a deferred task to // trigger another one, but still prevent the shell to be activated in a deferred task. await scope.UsingAsync(async scope => { diff --git a/src/OrchardCore/OrchardCore/Modules/Extensions/ServiceCollectionExtensions.cs b/src/OrchardCore/OrchardCore/Modules/Extensions/ServiceCollectionExtensions.cs index 8355c71c0f9..7314e21d9e8 100644 --- a/src/OrchardCore/OrchardCore/Modules/Extensions/ServiceCollectionExtensions.cs +++ b/src/OrchardCore/OrchardCore/Modules/Extensions/ServiceCollectionExtensions.cs @@ -10,7 +10,6 @@ using Microsoft.AspNetCore.DataProtection.XmlEncryption; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Json; using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Localization; @@ -155,11 +154,12 @@ private static void AddDefaultServices(OrchardCoreBuilder builder) services.AddSingleton(); - services.AddTransient, JsonOptionsConfigurations>(); + services.AddTransient, JsonOptionsConfigurations>(); services.AddTransient, DocumentJsonSerializerOptionsConfiguration>(); services.AddScoped(); services.AddSingleton(); + services.AddSingleton(); builder.ConfigureServices((services, serviceProvider) => { @@ -171,8 +171,6 @@ private static void AddDefaultServices(OrchardCoreBuilder builder) services.Configure(configuration.GetSection("OrchardCore_Localization_CultureOptions")); }); - - services.AddSingleton(); } private static void AddShellServices(OrchardCoreBuilder builder) @@ -197,6 +195,7 @@ private static void AddShellServices(OrchardCoreBuilder builder) builder.ConfigureServices(shellServices => { + shellServices.AddScoped(); shellServices.AddTransient, ShellContextOptionsSetup>(); shellServices.AddNullFeatureProfilesService(); shellServices.AddFeatureValidation(); diff --git a/src/OrchardCore/OrchardCore/Shell/DefaultShellReleaseManager.cs b/src/OrchardCore/OrchardCore/Shell/DefaultShellReleaseManager.cs new file mode 100644 index 00000000000..cbb12b69fc0 --- /dev/null +++ b/src/OrchardCore/OrchardCore/Shell/DefaultShellReleaseManager.cs @@ -0,0 +1,42 @@ +using Microsoft.Extensions.DependencyInjection; +using OrchardCore.Environment.Shell.Scope; + +namespace OrchardCore.Environment.Shell; + +public class DefaultShellReleaseManager : IShellReleaseManager +{ + private bool _release; + private bool _deferredTaskAdded; + + public void SuspendReleaseRequest() + { + _release = false; + } + + public void RequestRelease() + { + _release = true; + + if (_deferredTaskAdded) + { + return; + } + + _deferredTaskAdded = true; + + ShellScope.AddDeferredTask(async scope => + { + if (!_release) + { + return; + } + + _release = false; + + var shellHost = scope.ServiceProvider.GetRequiredService(); + var shellSettings = scope.ServiceProvider.GetRequiredService(); + + await shellHost.ReleaseShellContextAsync(shellSettings); + }); + } +} diff --git a/src/docs/releases/1.9.0.md b/src/docs/releases/1.9.0.md index 1c1da3d520a..42c010b994f 100644 --- a/src/docs/releases/1.9.0.md +++ b/src/docs/releases/1.9.0.md @@ -392,4 +392,93 @@ Enhanced functionality has been implemented, giving developers the ability to co ```csharp services.Configure(options => options.TokenLifespan = TimeSpan.FromDays(7)); ``` - \ No newline at end of file + +### Reloading Tenants + +The recent addition in the [Pull Request](https://github.com/OrchardCMS/OrchardCore/pull/15875) introduces the `IShellReleaseManager`, enabling you to initiate a shell release at the request's conclusion via the `RequestRelease()` method. This action is accessible from any service within the application. However, there's no assurance of immediate fulfillment since another service may utilize the same service and suspend the release request later. Should you need to suspend the request to release the shell, you can utilize the `SuspendReleaseRequest()` method to suspend the tenant release request and the tenant will not be released. + +#### Reloading Tenants Display Drivers + +When implementing a site settings display driver, you have the option to reload the shell (restart the tenant). If you choose to do so, manually releasing the shell context using `await _shellHost.ReleaseShellContextAsync(_shellSettings)` is unnecessary. Instead, you should use the new `IShellReleaseManager.RequestRelease()`. This ensures that the shell stays intact until all settings are validated. For instance, in `ReverseProxySettingsDisplayDriver`, the code was modified from this: + +```csharp +public class ReverseProxySettingsDisplayDriver : SectionDisplayDriver +{ + // + // For example simplicity, other methods are not visible. + // + + public override async Task UpdateAsync(ReverseProxySettings section, UpdateEditorContext context) + { + var user = _httpContextAccessor.HttpContext?.User; + + if (!await _authorizationService.AuthorizeAsync(user, Permissions.ManageReverseProxySettings)) + { + return null; + } + + if (context.GroupId.EqualsOrdinalIgnoreCase(GroupId)) + { + // + // For example simplicity, other logic are not visible. + // + + // If the settings are valid, release the current tenant. + if (context.Updater.ModelState.IsValid) + { + await _shellHost.ReleaseShellContextAsync(_shellSettings); + } + } + + return await EditAsync(section, context); + } +} +``` + +To this: + +```csharp +public class ReverseProxySettingsDisplayDriver : SectionDisplayDriver +{ + private readonly IShellReleaseManager _shellReleaseManager; + private readonly IHttpContextAccessor _httpContextAccessor; + private readonly IAuthorizationService _authorizationService; + + public ReverseProxySettingsDisplayDriver( + // (1) Inject the new service. + IShellReleaseManager shellReleaseManager + IHttpContextAccessor httpContextAccessor, + IAuthorizationService authorizationService) + { + _shellReleaseManager = shellReleaseManager; + _httpContextAccessor = httpContextAccessor; + _authorizationService = authorizationService; + } + + // + // For example simplicity, other methods are not visible. + // + + public override async Task UpdateAsync(ReverseProxySettings settings, UpdateEditorContext context) + { + var user = _httpContextAccessor.HttpContext?.User; + + if (!await _authorizationService.AuthorizeAsync(user, Permissions.ManageReverseProxySettings)) + { + return null; + } + + if (context.GroupId.EqualsOrdinalIgnoreCase(GroupId)) + { + // + // For example simplicity, other logic are not visible. + // + + // (2) Request a release at the end of the request. + _shellReleaseManager.RequestRelease(); + } + + return await EditAsync(settings, context); + } +} +```