diff --git a/src/OrchardCore.Modules/OrchardCore.Alias/Razor/AliasPartRazorHelperExtensions.cs b/src/OrchardCore.Modules/OrchardCore.Alias/Razor/AliasPartRazorHelperExtensions.cs index a6fb4c42d96..17b4615aa11 100644 --- a/src/OrchardCore.Modules/OrchardCore.Alias/Razor/AliasPartRazorHelperExtensions.cs +++ b/src/OrchardCore.Modules/OrchardCore.Alias/Razor/AliasPartRazorHelperExtensions.cs @@ -31,7 +31,7 @@ public static async Task GetContentItemIdByAliasAsync(this IOrchardHelpe } var session = orchardHelper.HttpContext.RequestServices.GetService(); - var aliasPartIndex = await AliasPartContentHandleHelper.QueryAliasIndex(session, alias); + var aliasPartIndex = await AliasPartContentHandleHelper.QueryAliasIndexAsync(session, alias); return aliasPartIndex?.ContentItemId; } diff --git a/src/OrchardCore.Modules/OrchardCore.Alias/Services/AliasPartContentHandleHelper.cs b/src/OrchardCore.Modules/OrchardCore.Alias/Services/AliasPartContentHandleHelper.cs new file mode 100644 index 00000000000..d56ba340143 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Alias/Services/AliasPartContentHandleHelper.cs @@ -0,0 +1,30 @@ +using System.Threading; +using System.Threading.Tasks; +using OrchardCore.Alias.Indexes; +using OrchardCore.ContentManagement; +using YesSql; + +namespace OrchardCore.Alias.Services +{ + internal sealed class AliasPartContentHandleHelper + { + private static readonly SemaphoreSlim _yesSqlLock = new(1, 1); + +#pragma warning disable CA1862 // Use the 'StringComparison' method overloads to perform case-insensitive string comparisons + internal static async Task QueryAliasIndexAsync(ISession session, string alias) + { + // NOTE: YesSql/Dapper does not support parallel or concurrent requests. + // Doing so can cause an `InvalidOperationException`, with the connection stuck within a "connecting" state. + await _yesSqlLock.WaitAsync(); + try + { + return await session.Query(x => x.Alias == alias.ToLowerInvariant()).FirstOrDefaultAsync(); + } + finally + { + _yesSqlLock?.Release(); + } + } +#pragma warning restore CA1862 // Use the 'StringComparison' method overloads to perform case-insensitive string comparisons + } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Alias/Services/AliasPartContentHandleProvider.cs b/src/OrchardCore.Modules/OrchardCore.Alias/Services/AliasPartContentHandleProvider.cs index 8388a62709d..5e257652af2 100644 --- a/src/OrchardCore.Modules/OrchardCore.Alias/Services/AliasPartContentHandleProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Alias/Services/AliasPartContentHandleProvider.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -using OrchardCore.Alias.Indexes; using OrchardCore.ContentManagement; using YesSql; @@ -23,19 +22,11 @@ public async Task GetContentItemIdAsync(string handle) { handle = handle[6..]; - var aliasPartIndex = await AliasPartContentHandleHelper.QueryAliasIndex(_session, handle); + var aliasPartIndex = await AliasPartContentHandleHelper.QueryAliasIndexAsync(_session, handle); return aliasPartIndex?.ContentItemId; } return null; } } - - internal sealed class AliasPartContentHandleHelper - { -#pragma warning disable CA1862 // Use the 'StringComparison' method overloads to perform case-insensitive string comparisons - internal static Task QueryAliasIndex(ISession session, string alias) => - session.Query(x => x.Alias == alias.ToLowerInvariant()).FirstOrDefaultAsync(); -#pragma warning restore CA1862 // Use the 'StringComparison' method overloads to perform case-insensitive string comparisons - } }