From a48057fe936804a0f87c78798253959f28b30891 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Wed, 1 May 2024 12:43:55 -0700 Subject: [PATCH 01/15] Convert v1.9 to v2.0 Fix #15892 --- src/OrchardCore.Build/OrchardCore.Commons.props | 2 +- src/docs/releases/{1.9.0.md => 2.0.0.md} | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) rename src/docs/releases/{1.9.0.md => 2.0.0.md} (98%) diff --git a/src/OrchardCore.Build/OrchardCore.Commons.props b/src/OrchardCore.Build/OrchardCore.Commons.props index 68598319ed7..94596c1d695 100644 --- a/src/OrchardCore.Build/OrchardCore.Commons.props +++ b/src/OrchardCore.Build/OrchardCore.Commons.props @@ -4,7 +4,7 @@ 12.0 - 1.9.0 + 2.0.0 preview $(VersionSuffix)-$(BuildNumber) 612,618 diff --git a/src/docs/releases/1.9.0.md b/src/docs/releases/2.0.0.md similarity index 98% rename from src/docs/releases/1.9.0.md rename to src/docs/releases/2.0.0.md index 1c1da3d520a..4d44579548a 100644 --- a/src/docs/releases/1.9.0.md +++ b/src/docs/releases/2.0.0.md @@ -1,7 +1,11 @@ -# Orchard Core 1.9.0 +# Orchard Core 2.0.0 Release date: Not yet released +## Upgrade Instructions + +Before upgrading to OrchardCore, you should first upgrade to 1.8, address any warning, then upgrade to 2.0. Be sure to review the list of breaking changes documented below to ensure seamless transition. + ## Breaking Changes ### Drop `Newtonsoft.Json` Support From b45218e3d83c1e88aa471b05aeafc64c2bca71a5 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Wed, 1 May 2024 13:00:29 -0700 Subject: [PATCH 02/15] Update src/docs/releases/2.0.0.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoltán Lehóczky --- src/docs/releases/2.0.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/docs/releases/2.0.0.md b/src/docs/releases/2.0.0.md index 4d44579548a..45740af0fac 100644 --- a/src/docs/releases/2.0.0.md +++ b/src/docs/releases/2.0.0.md @@ -4,7 +4,7 @@ Release date: Not yet released ## Upgrade Instructions -Before upgrading to OrchardCore, you should first upgrade to 1.8, address any warning, then upgrade to 2.0. Be sure to review the list of breaking changes documented below to ensure seamless transition. +Before upgrading to Orchard Core 2.0, you should first upgrade to 1.8, address any warnings, and only then upgrade to 2.0. Be sure to review the list of breaking changes documented below to ensure a seamless transition. ## Breaking Changes From 5b782ce6376ddaffd983f6a37cd32a3820e086a1 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Wed, 1 May 2024 13:30:30 -0700 Subject: [PATCH 03/15] fix build --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 5acbd170558..eac3cd84288 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -52,7 +52,7 @@ validation: # Add files here that are intentionally not in the navigation and thus omitted_files shouldn't warn about them. not_in_nav: | samples/ - releases/1.9.0.md + releases/2.0.0.md # Extensions markdown_extensions: From ddd67d37e00c74037ad11c631d84ac932c4be194 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Tue, 30 Apr 2024 13:50:48 -0700 Subject: [PATCH 04/15] Revert "Remove redirect to index after update. (#15679)" (#15925) --- .../OrchardCore.Settings/Controllers/AdminController.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/OrchardCore.Modules/OrchardCore.Settings/Controllers/AdminController.cs b/src/OrchardCore.Modules/OrchardCore.Settings/Controllers/AdminController.cs index 3961430168d..fac76003b44 100644 --- a/src/OrchardCore.Modules/OrchardCore.Settings/Controllers/AdminController.cs +++ b/src/OrchardCore.Modules/OrchardCore.Settings/Controllers/AdminController.cs @@ -92,6 +92,8 @@ public async Task IndexPost(string groupId) { await _notifier.SuccessAsync(H["Site settings updated successfully."]); } + + return RedirectToAction(nameof(Index), new { groupId }); } return View(viewModel); From dccc82ef29b5814327b19de3daa4f1b0dc272f7f Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Wed, 1 May 2024 08:36:35 +0300 Subject: [PATCH 05/15] Move UserType to OC.Users.Core (#15926) --- .../OrchardCore.ContentFields/OrchardCore.ContentFields.csproj | 1 - .../OrchardCore.Users.Core}/GraphQL/UserType.cs | 0 .../OrchardCore.Users.Core/OrchardCore.Users.Core.csproj | 1 + .../Services/CustomUserSettingsService.cs | 0 4 files changed, 1 insertion(+), 1 deletion(-) rename src/{OrchardCore.Modules/OrchardCore.Users => OrchardCore/OrchardCore.Users.Core}/GraphQL/UserType.cs (100%) rename src/{OrchardCore.Modules/OrchardCore.Users => OrchardCore/OrchardCore.Users.Core}/Services/CustomUserSettingsService.cs (100%) diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/OrchardCore.ContentFields.csproj b/src/OrchardCore.Modules/OrchardCore.ContentFields/OrchardCore.ContentFields.csproj index 4bfe9e3d2aa..d1666948809 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/OrchardCore.ContentFields.csproj +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/OrchardCore.ContentFields.csproj @@ -33,7 +33,6 @@ - diff --git a/src/OrchardCore.Modules/OrchardCore.Users/GraphQL/UserType.cs b/src/OrchardCore/OrchardCore.Users.Core/GraphQL/UserType.cs similarity index 100% rename from src/OrchardCore.Modules/OrchardCore.Users/GraphQL/UserType.cs rename to src/OrchardCore/OrchardCore.Users.Core/GraphQL/UserType.cs diff --git a/src/OrchardCore/OrchardCore.Users.Core/OrchardCore.Users.Core.csproj b/src/OrchardCore/OrchardCore.Users.Core/OrchardCore.Users.Core.csproj index 6bb859c4079..dfe002f36c0 100644 --- a/src/OrchardCore/OrchardCore.Users.Core/OrchardCore.Users.Core.csproj +++ b/src/OrchardCore/OrchardCore.Users.Core/OrchardCore.Users.Core.csproj @@ -17,6 +17,7 @@ + diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Services/CustomUserSettingsService.cs b/src/OrchardCore/OrchardCore.Users.Core/Services/CustomUserSettingsService.cs similarity index 100% rename from src/OrchardCore.Modules/OrchardCore.Users/Services/CustomUserSettingsService.cs rename to src/OrchardCore/OrchardCore.Users.Core/Services/CustomUserSettingsService.cs From 78d246a6ea0593c06d54d83093f9294ef5556c90 Mon Sep 17 00:00:00 2001 From: Antoine Griffard Date: Wed, 1 May 2024 15:03:07 +0200 Subject: [PATCH 06/15] mkdocs-git-revision-date-localized-plugin 1.2.5 --- src/docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/docs/requirements.txt b/src/docs/requirements.txt index 485c3c3c8a6..9eecd753458 100644 --- a/src/docs/requirements.txt +++ b/src/docs/requirements.txt @@ -1,7 +1,7 @@ mkdocs>=1.6.0 mkdocs-material>=9.5.20 mkdocs-git-authors-plugin>=0.8.0 -mkdocs-git-revision-date-localized-plugin>=1.2.4 +mkdocs-git-revision-date-localized-plugin>=1.2.5 pymdown-extensions>=10.8.1 mkdocs-exclude>=1.0.2 mkdocs-redirects>=1.2.1 From 9cbd208e4699da41b8b41544c9dc657fc30637ae Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Wed, 1 May 2024 18:13:53 +0300 Subject: [PATCH 07/15] Update OpenIddict 5.5.0 (#15910) --- src/OrchardCore.Build/Dependencies.props | 10 +++++----- src/docs/resources/libraries/README.md | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/OrchardCore.Build/Dependencies.props b/src/OrchardCore.Build/Dependencies.props index b0664efe2dd..5c30eb5a693 100644 --- a/src/OrchardCore.Build/Dependencies.props +++ b/src/OrchardCore.Build/Dependencies.props @@ -53,11 +53,11 @@ - - - - - + + + + + diff --git a/src/docs/resources/libraries/README.md b/src/docs/resources/libraries/README.md index 984a2e303b7..d05b87d54da 100644 --- a/src/docs/resources/libraries/README.md +++ b/src/docs/resources/libraries/README.md @@ -40,7 +40,7 @@ The below table lists the different .NET libraries used in Orchard Core: | [NJsonSchema](https://github.com/RicoSuter/NJsonSchema) | JSON Schema reader, generator and validator for .NET | 11.0.0 | [MIT](https://github.com/RicoSuter/NJsonSchema/blob/master/LICENSE.md) | | [NLog.Web.AspNetCore](https://github.com/NLog/NLog.Web/tree/master/src/NLog.Web.AspNetCore) | NLog integration for ASP.NET. | 5.3.8 | [BSD-3-Clause](https://github.com/NLog/NLog.Web/blob/master/LICENSE) | | [Noda Time](https://github.com/nodatime/nodatime) | A better date and time API for .NET. | 3.1.11 | [Apache-2.0](https://github.com/nodatime/nodatime/blob/master/LICENSE.txt) | -| [OpenIddict](https://github.com/openiddict/openiddict-core) | Flexible and versatile OAuth 2.0/OpenID Connect stack for .NET. | 5.4.0 | [Apache-2.0](https://github.com/openiddict/openiddict-core/blob/dev/LICENSE.md)) | +| [OpenIddict](https://github.com/openiddict/openiddict-core) | Flexible and versatile OAuth 2.0/OpenID Connect stack for .NET. | 5.5.0 | [Apache-2.0](https://github.com/openiddict/openiddict-core/blob/dev/LICENSE.md) | | [PdfPig](https://github.com/UglyToad/PdfPig/) | Library to read and extract text and other content from PDF files. | 0.1.8 | [Apache-2.0](https://github.com/UglyToad/PdfPig/blob/master/LICENSE) | | [Serilog.AspNetCore](https://github.com/serilog/serilog-aspnetcore) | Serilog integration for ASP.NET Core. | 8.0.1 | [Apache-2.0](https://github.com/serilog/serilog-aspnetcore/blob/dev/LICENSE) | | [Shortcodes](https://github.com/sebastienros/shortcodes) | Shortcodes processor for .NET. | 1.3.3 | [MIT](https://github.com/sebastienros/shortcodes/blob/dev/LICENSE) | From a5030ac3451c595226aa27b97239e8df9f0d782a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Leh=C3=B3czky?= Date: Wed, 1 May 2024 17:16:41 +0200 Subject: [PATCH 08/15] Remove leftover issue_metrics workflow (#15932) --- .github/workflows/community_metrics.yml | 2 +- .github/workflows/issue_metrics.yml | 81 ------------------------- 2 files changed, 1 insertion(+), 82 deletions(-) delete mode 100644 .github/workflows/issue_metrics.yml diff --git a/.github/workflows/community_metrics.yml b/.github/workflows/community_metrics.yml index 0e010ddbf32..720799ab124 100644 --- a/.github/workflows/community_metrics.yml +++ b/.github/workflows/community_metrics.yml @@ -10,7 +10,7 @@ permissions: pull-requests: read jobs: - build: + generate-community-metrics: name: Generate Community Metrics runs-on: ubuntu-latest steps: diff --git a/.github/workflows/issue_metrics.yml b/.github/workflows/issue_metrics.yml deleted file mode 100644 index 4ebbef489b6..00000000000 --- a/.github/workflows/issue_metrics.yml +++ /dev/null @@ -1,81 +0,0 @@ -name: Monthly Issue and Pull Request Metrics -on: - workflow_dispatch: - schedule: - # Run on the first day of every month at 2:19 AM UTC. - - cron: '19 2 1 * *' - -permissions: - issues: write - pull-requests: read - -jobs: - publish-issue-metrics: - name: Generate Issue and Pull Request Metrics - runs-on: ubuntu-latest - steps: - - name: Get Dates For Last Month - shell: pwsh - run: | - # Calculate the first day of the previous month. - $firstDay = (Get-Date).AddMonths(-1).ToString("yyyy-MM-01") - - # Calculate the last day of the previous month. - $lastDay = (Get-Date $firstDay).AddMonths(1).AddDays(-1).ToString("yyyy-MM-dd") - - # Set an environment variable with the date range. - Write-Output "$firstDay..$lastDay" - Write-Output "LAST_MONTH=$firstDay..$lastDay" >> $env:GITHUB_ENV - - - name: Compute Issue Metrics - uses: github/issue-metrics@v2 - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SEARCH_QUERY: 'repo:OrchardCMS/OrchardCore is:issue created:${{ env.LAST_MONTH }} -reason:"not planned" -label:"community metrics"' - HIDE_TIME_TO_ANSWER: true - - - name: Rename Issue Metrics File - shell: pwsh - run: | - # Renaming the file wouldn't work since other scripts will be denied access to it for some reason. - Add-Content -Path ./community_metrics.md -Value (Get-Content -Path ./issue_metrics.md -Raw) - - - name: Compute Pull Request Metrics - uses: github/issue-metrics@v2 - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SEARCH_QUERY: 'repo:OrchardCMS/OrchardCore is:pr created:${{ env.LAST_MONTH }} -label:dontmerge -label:notready -is:draft' - HIDE_TIME_TO_ANSWER: true - - - name: Concatenate Issue and Pull Request Metrics - shell: pwsh - run: | - $content = (Get-Content -Path ./issue_metrics.md -Raw) -replace '# Issue Metrics', '# Pull Request Metrics' - Add-Content -Path ./community_metrics.md -Value ([Environment]::NewLine + $content) - - - name: Compute Q&A Discussion Request Metrics - uses: github/issue-metrics@v2 - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SEARCH_QUERY: 'repo:OrchardCMS/OrchardCore type:discussions created:${{ env.LAST_MONTH }} category:Q&A' - HIDE_TIME_TO_CLOSE: true - - - name: Concatenate Issue/PR and Discussion Metrics - shell: pwsh - run: | - $content = (Get-Content -Path ./issue_metrics.md -Raw) -replace '# Issue Metrics', '# Discussion Metrics' - Add-Content -Path ./community_metrics.md -Value ([Environment]::NewLine + $content) - - - name: Display Issue Metrics in Summary - shell: pwsh - run: | - Get-Content ./community_metrics.md >> $env:GITHUB_STEP_SUMMARY - - - name: Create Issue - # v4.0.1 - uses: peter-evans/create-issue-from-file@433e51abf769039ee20ba1293a088ca19d573b7f - with: - title: Monthly community metrics report for ${{ env.LAST_MONTH }} - token: ${{ secrets.GITHUB_TOKEN }} - content-filepath: ./community_metrics.md - labels: community metrics From 3c4a5ec271a20ac5feddf166c0df6d6ddfb0355a Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Wed, 1 May 2024 19:14:48 +0300 Subject: [PATCH 09/15] Update Jint 3.1.1 (#15912) --- src/OrchardCore.Build/Dependencies.props | 2 +- src/docs/resources/libraries/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OrchardCore.Build/Dependencies.props b/src/OrchardCore.Build/Dependencies.props index 5c30eb5a693..f644a5d8383 100644 --- a/src/OrchardCore.Build/Dependencies.props +++ b/src/OrchardCore.Build/Dependencies.props @@ -26,7 +26,7 @@ - + diff --git a/src/docs/resources/libraries/README.md b/src/docs/resources/libraries/README.md index d05b87d54da..ad1f5a7a95c 100644 --- a/src/docs/resources/libraries/README.md +++ b/src/docs/resources/libraries/README.md @@ -20,7 +20,7 @@ The below table lists the different .NET libraries used in Orchard Core: | [HtmlSanitizer](https://github.com/mganss/HtmlSanitizer) | Cleans HTML to avoid XSS attacks. | 8.1.860-beta | [MIT](https://github.com/mganss/HtmlSanitizer/blob/master/LICENSE.md) | | [ImageSharp](https://github.com/SixLabors/ImageSharp.Web) | Middleware for ASP.NET-Core for image manipulation. | 3.1.2 |[Apache-2.0](https://github.com/SixLabors/ImageSharp.Web/blob/master/LICENSE) | | [Irony.Core](https://github.com/daxnet/irony) | A modified version of the Irony project with .NET Core support | 1.0.7 | [MIT](https://github.com/daxnet/irony/blob/master/LICENSE) | -| [Jint](https://github.com/sebastienros/jint) | Javascript Interpreter for .NET. | 3.1.0 | [MIT](https://github.com/sebastienros/jint/blob/dev/LICENSE) | +| [Jint](https://github.com/sebastienros/jint) | Javascript Interpreter for .NET. | 3.1.1 | [MIT](https://github.com/sebastienros/jint/blob/dev/LICENSE) | | [libphonenumber-csharp](https://github.com/twcclegg/libphonenumber-csharp) | .NET library for parsing, formatting, and validating international phone numbers | 8.13.35 | [Apache-2.0](https://github.com/twcclegg/libphonenumber-csharp/blob/main/LICENSE) | | [Lorem.NET for netstandard](https://github.com/trichards57/Lorem.Universal.NET) | A .NET library for all things random! | 4.0.80 | [MIT](https://github.com/trichards57/Lorem.Universal.NET/blob/master/license.md) | | [Lucene.Net](https://github.com/apache/lucenenet) | .NET full-text search engine. | 4.8.0-beta00016 | [Apache-2.0](https://github.com/apache/lucenenet/blob/master/LICENSE.txt) | From 3630bd8f90fd6dbdf0bf813c3b33e7d41345fee4 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Wed, 1 May 2024 12:25:56 -0700 Subject: [PATCH 10/15] Prevent AliasPart index from throwing a null exception (#15934) --- .../OrchardCore.Alias/Indexes/AliasPartIndex.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Alias/Indexes/AliasPartIndex.cs b/src/OrchardCore.Modules/OrchardCore.Alias/Indexes/AliasPartIndex.cs index d93a5d1553c..632d326e7b2 100644 --- a/src/OrchardCore.Modules/OrchardCore.Alias/Indexes/AliasPartIndex.cs +++ b/src/OrchardCore.Modules/OrchardCore.Alias/Indexes/AliasPartIndex.cs @@ -44,7 +44,7 @@ public override async Task UpdatedAsync(UpdateContentContext context) // Search for this part. var contentTypeDefinition = await _contentDefinitionManager.GetTypeDefinitionAsync(context.ContentItem.ContentType); - if (!contentTypeDefinition.Parts.Any(ctd => ctd.Name == nameof(AliasPart))) + if (contentTypeDefinition?.Parts is not null && !contentTypeDefinition.Parts.Any(ctd => string.Equals(ctd.Name, nameof(AliasPart), StringComparison.Ordinal))) { context.ContentItem.Remove(); _partRemoved.Add(context.ContentItem.ContentItemId); From 211ae343fc3f674e4fc59b57702012312ac8f1a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Ros?= Date: Wed, 1 May 2024 14:32:20 -0700 Subject: [PATCH 11/15] Reduce allocations in ShellScope (#15937) --- .../Shell/Scope/ShellScope.cs | 92 ++++++++++++++----- 1 file changed, 69 insertions(+), 23 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Abstractions/Shell/Scope/ShellScope.cs b/src/OrchardCore/OrchardCore.Abstractions/Shell/Scope/ShellScope.cs index df79c757eea..200e8c5caef 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Shell/Scope/ShellScope.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Shell/Scope/ShellScope.cs @@ -19,11 +19,11 @@ public sealed class ShellScope : IServiceScope, IAsyncDisposable private static readonly AsyncLocal _current = new(); private readonly AsyncServiceScope _serviceScope; - private readonly Dictionary _items = []; - private readonly List> _beforeDispose = []; - private readonly HashSet _deferredSignals = []; - private readonly List> _deferredTasks = []; - private readonly List> _exceptionHandlers = []; + private Dictionary _items; + private List> _beforeDispose; + private HashSet _deferredSignals; + private List> _deferredTasks; + private List> _exceptionHandlers; private bool _serviceScopeOnly; private bool _shellTerminated; @@ -84,35 +84,68 @@ public ShellScope(ShellContext shellContext) /// public static void Set(object key, object value) { - if (Current is not null) + var current = Current; + + if (current != null) { - Current._items[key] = value; + current._items ??= []; + + current._items[key] = value; } } /// /// Gets a shared item from the current shell scope. /// - public static object Get(object key) => Current is null ? null : Current._items.TryGetValue(key, out var value) ? value : null; + public static object Get(object key) + { + var current = Current; + + if (current == null) + { + return null; + } + + current._items ??= []; + + return current._items.TryGetValue(key, out var value) ? value : null; + } /// /// Gets a shared item of a given type from the current shell scope. /// - public static T Get(object key) => Current is null ? default : Current._items.TryGetValue(key, out var value) ? value is T item ? item : default : default; + public static T Get(object key) + { + var current = Current; + + if (current == null) + { + return default; + } + + current._items ??= []; + + return current._items.TryGetValue(key, out var value) ? value is T item ? item : default : default; + } /// /// Gets (or creates) a shared item of a given type from the current shell scope. /// public static T GetOrCreate(object key, Func factory) { - if (Current is null) + var current = Current; + + if (current == null) { return factory(); } - if (!Current._items.TryGetValue(key, out var value) || value is not T item) + current._items ??= []; + + + if (!current._items.TryGetValue(key, out var value) || value is not T item) { - Current._items[key] = item = factory(); + current._items[key] = item = factory(); } return item; @@ -123,14 +156,19 @@ public static T GetOrCreate(object key, Func factory) /// public static T GetOrCreate(object key) where T : class, new() { - if (Current is null) + var current = Current; + + if (current == null) { return new T(); } - if (!Current._items.TryGetValue(key, out var value) || value is not T item) + current._items ??= []; + + + if (!current._items.TryGetValue(key, out var value) || value is not T item) { - Current._items[key] = item = new T(); + current._items[key] = item = new T(); } return item; @@ -338,22 +376,22 @@ internal async Task ActivateShellInternalAsync() /// /// Registers a delegate to be invoked when 'BeforeDisposeAsync()' is called on this scope. /// - internal void BeforeDispose(Func callback) => _beforeDispose.Insert(0, callback); + internal void BeforeDispose(Func callback) => (_beforeDispose ??= []).Insert(0, callback); /// /// Adds a Signal (if not already present) to be sent just after 'BeforeDisposeAsync()'. /// - internal void DeferredSignal(string key) => _deferredSignals.Add(key); + internal void DeferredSignal(string key) => (_deferredSignals ??= []).Add(key); /// /// Adds a Task to be executed in a new scope after 'BeforeDisposeAsync()'. /// - internal void DeferredTask(Func task) => _deferredTasks.Add(task); + internal void DeferredTask(Func task) => (_deferredTasks ??= []).Add(task); /// /// Adds an handler to be invoked if an exception is thrown while executing in this shell scope. /// - internal void ExceptionHandler(Func callback) => _exceptionHandlers.Add(callback); + internal void ExceptionHandler(Func callback) => (_exceptionHandlers ??= []).Add(callback); /// /// Registers a delegate to be invoked before the current shell scope will be disposed. @@ -380,6 +418,11 @@ internal async Task ActivateShellInternalAsync() /// public async Task HandleExceptionAsync(Exception e) { + if (_exceptionHandlers == null) + { + return; + } + foreach (var callback in _exceptionHandlers) { await callback(this, e); @@ -392,9 +435,12 @@ public async Task HandleExceptionAsync(Exception e) /// internal async Task BeforeDisposeAsync() { - foreach (var callback in _beforeDispose) + if (_beforeDispose != null) { - await callback(this); + foreach (var callback in _beforeDispose) + { + await callback(this); + } } if (_serviceScopeOnly) @@ -402,7 +448,7 @@ internal async Task BeforeDisposeAsync() return; } - if (_deferredSignals.Count > 0) + if (_deferredSignals?.Count > 0) { var signal = ShellContext.ServiceProvider.GetRequiredService(); foreach (var key in _deferredSignals) @@ -411,7 +457,7 @@ internal async Task BeforeDisposeAsync() } } - if (_deferredTasks.Count > 0) + if (_deferredTasks?.Count > 0) { var shellHost = ShellContext.ServiceProvider.GetRequiredService(); From 45f393b56b65266c6a738e57e7ce5120abad63c5 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Wed, 1 May 2024 15:27:03 -0700 Subject: [PATCH 12/15] Add a way to queue releasing shell context from setting display drivers (#15875) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoltán Lehóczky Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../AzureEmailSettingsDisplayDriver.cs | 12 +-- .../Drivers/SmtpSettingsDisplayDriver.cs | 12 +-- .../Drivers/EmailSettingsDisplayDriver.cs | 11 +-- .../Drivers/FacebookSettingsDisplayDriver.cs | 29 +++--- .../FacebookLoginSettingsDisplayDriver.cs | 23 ++--- ...thubAuthenticationSettingsDisplayDriver.cs | 13 ++- ...ogleAuthenticationSettingsDisplayDriver.cs | 20 ++-- .../Drivers/HttpsSettingsDisplayDriver.cs | 19 ++-- .../Drivers/LayerSiteSettingsDisplayDriver.cs | 3 +- .../LocalizationSettingsDisplayDriver.cs | 26 +++--- .../Drivers/AzureADSettingsDisplayDriver.cs | 31 +++---- .../MicrosoftAccountSettingsDisplayDriver.cs | 20 ++-- .../OpenIdClientSettingsDisplayDriver.cs | 16 +--- .../Drivers/ReCaptchaSettingsDisplayDriver.cs | 21 ++--- .../ReverseProxySettingsDisplayDriver.cs | 31 +++---- ...ureAISearchDefaultSettingsDisplayDriver.cs | 32 +++---- .../AzureAISearchSettingsDisplayDriver.cs | 25 ++--- .../Drivers/ElasticSettingsDisplayDriver.cs | 5 - .../Drivers/SecuritySettingsDisplayDriver.cs | 26 ++---- .../Drivers/RobotsSettingsDisplayDriver.cs | 1 + .../Controllers/AdminController.cs | 20 +++- .../DefaultSiteSettingsDisplayDriver.cs | 16 +--- .../Drivers/SmsSettingsDisplayDriver.cs | 11 +-- .../Drivers/TwilioSettingsDisplayDriver.cs | 13 +-- .../Drivers/TwitterSettingsDisplayDriver.cs | 18 ++-- .../TwitterSigninSettingsDisplayDriver.cs | 23 ++--- .../RegistrationSettingsDisplayDriver.cs | 1 + .../ResetPasswordSettingsDisplayDriver.cs | 1 + .../Drivers/RoleLoginSettingsDisplayDriver.cs | 1 + .../TwoFactorLoginSettingsDisplayDriver.cs | 1 + .../Shell/IShellReleaseManager.cs | 14 +++ .../Shell/Scope/ShellScope.cs | 2 +- .../Extensions/ServiceCollectionExtensions.cs | 7 +- .../Shell/DefaultShellReleaseManager.cs | 42 +++++++++ src/docs/releases/2.0.0.md | 91 ++++++++++++++++++- 35 files changed, 361 insertions(+), 276 deletions(-) create mode 100644 src/OrchardCore/OrchardCore.Abstractions/Shell/IShellReleaseManager.cs create mode 100644 src/OrchardCore/OrchardCore/Shell/DefaultShellReleaseManager.cs 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 200e8c5caef..cf2889fd8a7 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Shell/Scope/ShellScope.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Shell/Scope/ShellScope.cs @@ -476,7 +476,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/2.0.0.md b/src/docs/releases/2.0.0.md index 45740af0fac..4906bd3f954 100644 --- a/src/docs/releases/2.0.0.md +++ b/src/docs/releases/2.0.0.md @@ -396,4 +396,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); + } +} +``` From f6019c6be90eec4661aab5be537481799509fd8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Ros?= Date: Wed, 1 May 2024 15:36:44 -0700 Subject: [PATCH 13/15] Use dotnet ForEachAsync implementation (#15936) Co-authored-by: Mike Alhayek --- .../Extensions/EnumerableExtensions.cs | 29 ------------------- .../Extensions/ExtensionManager.cs | 6 ++-- .../Modules/ModularBackgroundService.cs | 4 +-- 3 files changed, 4 insertions(+), 35 deletions(-) delete mode 100644 src/OrchardCore/OrchardCore.Abstractions/Modules/Extensions/EnumerableExtensions.cs diff --git a/src/OrchardCore/OrchardCore.Abstractions/Modules/Extensions/EnumerableExtensions.cs b/src/OrchardCore/OrchardCore.Abstractions/Modules/Extensions/EnumerableExtensions.cs deleted file mode 100644 index 987cea11774..00000000000 --- a/src/OrchardCore/OrchardCore.Abstractions/Modules/Extensions/EnumerableExtensions.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace OrchardCore.Modules -{ - public static class EnumerableExtensions - { - public static Task ForEachAsync(this IEnumerable source, Func body) - { - var partitionCount = System.Environment.ProcessorCount; - - return Task.WhenAll( - from partition in Partitioner.Create(source).GetPartitions(partitionCount) - select Task.Run(async delegate - { - using (partition) - { - while (partition.MoveNext()) - { - await body(partition.Current); - } - } - })); - } - } -} diff --git a/src/OrchardCore/OrchardCore/Extensions/ExtensionManager.cs b/src/OrchardCore/OrchardCore/Extensions/ExtensionManager.cs index cc01db9ba35..9988672d1f3 100644 --- a/src/OrchardCore/OrchardCore/Extensions/ExtensionManager.cs +++ b/src/OrchardCore/OrchardCore/Extensions/ExtensionManager.cs @@ -298,11 +298,11 @@ private async Task EnsureInitializedAsync() var loadedExtensions = new ConcurrentDictionary(); // Load all extensions in parallel - await modules.ForEachAsync((module) => + Parallel.ForEach(modules, (module, cancellationToken) => { if (!module.ModuleInfo.Exists) { - return Task.CompletedTask; + return; } var manifestInfo = new ManifestInfo(module.ModuleInfo); @@ -319,8 +319,6 @@ await modules.ForEachAsync((module) => }; loadedExtensions.TryAdd(module.Name, entry); - - return Task.CompletedTask; }); var loadedFeatures = new Dictionary(); diff --git a/src/OrchardCore/OrchardCore/Modules/ModularBackgroundService.cs b/src/OrchardCore/OrchardCore/Modules/ModularBackgroundService.cs index 1e7a0c2df72..ef8c40c0428 100644 --- a/src/OrchardCore/OrchardCore/Modules/ModularBackgroundService.cs +++ b/src/OrchardCore/OrchardCore/Modules/ModularBackgroundService.cs @@ -102,7 +102,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) private async Task RunAsync(IEnumerable<(string Tenant, long UtcTicks)> runningShells, CancellationToken stoppingToken) { - await GetShellsToRun(runningShells).ForEachAsync(async tenant => + await Parallel.ForEachAsync(GetShellsToRun(runningShells), async (tenant, cancellationToken) => { // Check if the shell is still registered and running. if (!_shellHost.TryGetShellContext(tenant, out var shell) || !shell.Settings.IsRunning()) @@ -238,7 +238,7 @@ private async Task UpdateAsync( { var referenceTime = DateTime.UtcNow; - await GetShellsToUpdate(previousShells, runningShells).ForEachAsync(async tenant => + await Parallel.ForEachAsync(GetShellsToUpdate(previousShells, runningShells), async (tenant, cancellationToken) => { if (stoppingToken.IsCancellationRequested) { From 2c3527781a62784980a48e97b9d68cb537e62fec Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Thu, 2 May 2024 02:04:31 +0300 Subject: [PATCH 14/15] Replace IDataMigrationManager.UpdateAsync(string) with IDataMigrationManager.UpdateAsync(IEnumerable) (#15909) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoltán Lehóczky --- .../IDataMigrationManager.cs | 10 ++++++---- .../Migration/DataMigrationManager.cs | 9 ++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Data.Abstractions/IDataMigrationManager.cs b/src/OrchardCore/OrchardCore.Data.Abstractions/IDataMigrationManager.cs index 80f070e968c..1082e5661f5 100644 --- a/src/OrchardCore/OrchardCore.Data.Abstractions/IDataMigrationManager.cs +++ b/src/OrchardCore/OrchardCore.Data.Abstractions/IDataMigrationManager.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Threading.Tasks; @@ -22,13 +23,14 @@ public interface IDataMigrationManager /// Updates the database to the latest version for the specified feature. /// /// The feature to be uninstalled. - Task UpdateAsync(string feature); + [Obsolete("This method has been deprecated, please use UpdateAsync(string[] features) instead.")] + Task UpdateAsync(string feature) => UpdateAsync([feature]); /// - /// Updates the database to the latest version for the specified features. + /// Updates the database to the latest version for the specified feature(s). /// - /// The features to be updated. - Task UpdateAsync(IEnumerable features); + /// The feature(s) to be updated. + Task UpdateAsync(params string[] features); /// /// Execute a script to delete any information relative to the feature. diff --git a/src/OrchardCore/OrchardCore.Data.YesSql/Migration/DataMigrationManager.cs b/src/OrchardCore/OrchardCore.Data.YesSql/Migration/DataMigrationManager.cs index 3a8530abaa4..594d72e1ad8 100644 --- a/src/OrchardCore/OrchardCore.Data.YesSql/Migration/DataMigrationManager.cs +++ b/src/OrchardCore/OrchardCore.Data.YesSql/Migration/DataMigrationManager.cs @@ -123,7 +123,7 @@ public async Task Uninstall(string feature) } } - public async Task UpdateAsync(IEnumerable featureIds) + public async Task UpdateAsync(params string[] featureIds) { foreach (var featureId in featureIds) { @@ -134,7 +134,7 @@ public async Task UpdateAsync(IEnumerable featureIds) } } - public async Task UpdateAsync(string featureId) + private async Task UpdateAsync(string featureId) { if (_processedFeatures.Contains(featureId)) { @@ -152,7 +152,10 @@ public async Task UpdateAsync(string featureId) .Where(x => x.Id != featureId) .Select(x => x.Id); - await UpdateAsync(dependencies); + foreach (var dependency in dependencies) + { + await UpdateAsync(dependency); + } var migrations = GetDataMigrations(featureId); From 94039f2f97bcef308c6b5f1aae5821324c893aab Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Wed, 1 May 2024 17:56:47 -0700 Subject: [PATCH 15/15] update --- .../OrchardCore.Email/Migrations/EmailMigrations.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Email/Migrations/EmailMigrations.cs b/src/OrchardCore.Modules/OrchardCore.Email/Migrations/EmailMigrations.cs index 7feb6a7f59b..131fc687e3a 100644 --- a/src/OrchardCore.Modules/OrchardCore.Email/Migrations/EmailMigrations.cs +++ b/src/OrchardCore.Modules/OrchardCore.Email/Migrations/EmailMigrations.cs @@ -16,7 +16,7 @@ public class EmailMigrations : DataMigration public int Create() #pragma warning restore CA1822 { - // In version 1.9, the OrchardCore.Email.Smtp was split from OrchardCore.Email. To ensure we keep the change + // In version 2.0, the OrchardCore.Email.Smtp was split from OrchardCore.Email. To ensure we keep the change // backward compatible, we added this migration step to auto-enable the new SMTP feature for sites that use the // Email service and have SmtpSettings. ShellScope.AddDeferredTask(async scope =>