В приложении Blazor InteractiveServer, используя библиотеку удостоверений ASP.NET, я вызываю: Microsoft.AspNetCore.Identity.UserManager`1.GetClaimsAsync (пользователь TUser)
Я настроил его на использование моего класса расширения, добавив его в Program.cs.
builder.Services.AddScoped<AuthenticationStateProvider, ExAuthenticationStateProvider>();
Помимо добавления этой строки, вся ее польза заключается в том, что стек Blazor вызывает ее, когда захочет. Единственный раз, когда я напрямую вызываю что-либо в этом классе, это когда я звоню ResetNextCheck()
.
И он выдает (полная трассировка стека ниже).
Microsoft.EntityFrameworkCore.Query - An exception occurred while iterating over the results of a query for context type 'LouisHowe.web.Areas.Identity.Data.UserDbContext'.
System.InvalidOperationException: Invalid operation. The connection is closed.
Таблица претензий имеет 34 записи, поэтому чтение всей таблицы, если это требуется (а это не так), происходит быстро.
Единственная нестандартная часть всего этого в моем приложении — это class ExIdentityUser : IdentityUser
, куда я добавляю public bool Enabled { get; set; }
. Итак, мой DbContext — UserDbContext : IdentityDbContext<ExIdentityUser>
.
Это происходит внутри моего ExAuthenticationStateProvider : ServerAuthenticationStateProvider
GetAuthenticationStateAsync()
метода.
Почему при этом вызове закрывается соединение?
Полный журнал:
Error 08:52:21 [] Microsoft.EntityFrameworkCore.Database.Command - Failed executing DbCommand (19ms) [Parameters=[@__user_Id_0='?' (Size = 450)], CommandType='Text', CommandTimeout='30']
SELECT [a].[Id], [a].[ClaimType], [a].[ClaimValue], [a].[UserId]
FROM [AspNetUserClaims] AS [a]
WHERE [a].[UserId] = @__user_Id_0
// 20 irrelevant log messages
Error 08:52:22 [] Microsoft.EntityFrameworkCore.Query - An exception occurred while iterating over the results of a query for context type 'LouisHowe.web.Areas.Identity.Data.UserDbContext'.
System.InvalidOperationException: Invalid operation. The connection is closed.
at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync() InvalidOperationException: Invalid operation. The connection is closed.
at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
Error 08:52:22 [] LouisHowe.web.Services.ExAuthenticationStateProvider - GetAuthenticationStateAsync() exception: Invalid operation. The connection is closed. InvalidOperationException: Invalid operation. The connection is closed.
at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserOnlyStore`6.GetClaimsAsync(TUser user, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Identity.UserManager`1.GetClaimsAsync(TUser user)
at LouisHowe.web.Services.ExAuthenticationStateProvider.GetAuthenticationStateAsync() in D:\a\LouisHowe\LouisHowe\LouisHowe.web\Services\ExAuthenticationStateProvider.cs:line 94
@HenkHolterman Я добавил, как он внедряется и т. д. Все, что я делаю, это вызов AddScoped()
в Program.cs. Когда он вызывается, ожидается и т. д., это Blazor и/или библиотека удостоверений. Я также нашел исправление (добавленное ниже), но понятия не имею, почему это его исправляет, что меня всегда беспокоит. Спасибо
Я это исправил (объяснение ниже). С учетом сказанного, я не знаю, почему это исправляет.
Я использовал UserManager<ExIdentityUser>
, чтобы вызвать:
userManager.FindByIdAsync(id);
userManager.GetClaimsAsync(user);
Эти вызовы иногда терпели неудачу, поскольку базовый DbConnection был закрыт. Я понятия не имею, почему, тем более что иногда вызов FindByIdAsync()
завершался успешно, тогда следующий вызов GetClaimsAsync()
имел бы закрытое соединение.
Чтобы обойти это, я изменил его на использование:
IDbContextFactory<UserDbContext> UserDbFactory;
var dbContext = await UserDbFactory.CreateDbContextAsync();
var user = await dbContext.Users.Where(u => u.Id == id).FirstOrDefaultAsync();
var list = await dbContext.UserClaims.Where(uc => uc.UserId == id).ToListAsync();
Это не только решило мою проблему с иногда закрытием DbConnection, но и решило эту проблему. Как я уже сказал выше, понятия не имею, почему. Но вызов методов UserManager
привел к сбою NotifyAuthenticationStateChanged()
. Переход на UserDbFactory
устранил эту проблему, а также другую проблему.
Приводят ли другие запросы к той же ошибке? Приложение по-прежнему работает нормально после получения этой ошибки? Можете ли вы показать точный код, который вам нужен для получения претензий через диспетчер пользователей?