C# Blazor - 修复 "This connection was used with an ambient transaction..."

C# Blazor - Fix "This connection was used with an ambient transaction..."

我在 Blazor 页面中添加了一个计时器,因此一些数据(从数据库中提取)可以每 5 秒刷新一次。当我在页面上时它工作正常,但是当我移动到另一个页面并返回到原始页面时,我收到此错误:

"This connection was used with an ambient transaction. The original ambient transaction needs to be completed before this connection can be used outside of it" I've included the stack trace at the end

我试过在页面处理时处理Timer,但没有解决。看起来这个问题是由于数据库上下文是如何在依赖注入容器中注册的,但是

这是我页面的 C# 代码。它调用主服务,后者又通过存储库获取数据。

@functions {

    protected Dictionary<int, int> RunningTaskProcessQueueCountDictionary;
    protected Dictionary<int, int> PendingTaskProcessQueueCountDictionary;
    protected Timer CountRefreshTimer = null;

    protected override async Task OnInitAsync()
    {
        CountRefreshTimer = new Timer(new TimerCallback(async _ =>
        {
            await RefreshCount();
            await base.Invoke(StateHasChanged);
        }), null, 0, 5000);
    }


    private async Task RefreshCount()
    {
        RunningTaskProcessQueueCountDictionary = await mainService.GetRunningTaskProcessQueueCountByTaskAppAsync(null);
        PendingTaskProcessQueueCountDictionary = await mainService.GetPendingTaskProcessQueueCountByTaskAppAsync(null);
    }

    public void Dispose()
    {
        if (CountRefreshTimer != null)
        {
            CountRefreshTimer.Dispose();
        }
    }
}

这是注册数据库上下文的 startup.cs 的摘录:

// Register the DB Context
var connection = Configuration.GetConnectionString("SQL01.xxx");
services.AddDbContext<SQL01xxxContext>(options => options.UseSqlServer(connection));

// Register all repositories and services (using Scrutor)
services.Scan(scan =>
    scan.FromAssemblies(typeof(IMainService).Assembly, typeof(ITaskAppRepository).Assembly)
        .AddClasses()
        .AsMatchingInterface()
        .WithScopedLifetime());

services.AddScoped<DbContext, SQL01xxxContext>();
services.AddScoped<IUnitOfWork<SQL01xxxContext>, UnitOfWork<SQL01xxxContext>>();

这是错误的堆栈跟踪

System.InvalidOperationException HResult=0x80131509 Message=This connection was used with an ambient transaction. The original ambient transaction needs to be completed before this connection can be used outside of it. Source=Microsoft.EntityFrameworkCore.Relational
StackTrace: at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.HandleAmbientTransactions() at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.d__42.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable1.AsyncEnumerator.d__12.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.<ExecuteAsync>d__72.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable1.AsyncEnumerator.d__11.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.ConfiguredTaskAwaitable1.ConfiguredTaskAwaiter.GetResult() at System.Linq.AsyncEnumerable.SelectEnumerableAsyncIterator2.d__7.MoveNext() in D:\a\s\Ix.NET\Source\System.Interactive.Async\Select.cs:line 106 at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.ConfiguredTaskAwaitable1.ConfiguredTaskAwaiter.GetResult() at System.Linq.AsyncEnumerable.AsyncIterator1.d__10.MoveNext() in D:\a\s\Ix.NET\Source\System.Interactive.Async\AsyncIterator.cs:line 112 at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor1.EnumeratorExceptionInterceptor.d__5.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Linq.AsyncEnumerable.d__63.MoveNext() in D:\a\s\Ix.NET\Source\System.Interactive.Async\Aggregate.cs:line 120 at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() at SIQC.Enterprise.GenericRepository.Common.IQueryableExtensions.d__11.MoveNext() in C:\TFS\[...]\IQueryableExtensions.cs:line 28 at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() at SIQC.Enterprise.GenericRepository.RepositoryBase.ReadOnlyRepository1.<GetAsync>d__12.MoveNext() in C:\TFS\[...]\ReadOnlyRepository.cs:line 174 at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() at ToolsWebManagementData.IntravexV21.Repository.TaskProcessQueueRepository.d__2.MoveNext() in C:\TFS[...]\TaskProcessQueueRepository.cs:line 46 at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() at TWMBlazorSSB.Services.MainService.<GetRunningTaskProcessQueueCountByTaskAppAsync>d__21.MoveNext() in C:\TFS\[...]\MainService.cs:line 79 at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() at TWMBlazorSSB.Pages.TaskApp.TaskApps.d__7.MoveNext() in C:\TFS[...]\TaskApps.razor:line 91 at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at TWMBlazorSSB.Pages.TaskApp.TaskApps.<b__6_0>d.MoveNext() in C:\TFS[...]\TaskApps.razor:line 79

如有任何帮助,我们将不胜感激。 谢谢

It looks like this issue is due to how the DB context is registered

没错。这是因为 AddDbContext<> 使用(默认)ServiceLifetime.Scoped。但是没有有用的范围。

这仍然是 under discussion by the Blazor team,也许在考虑解决方法之前等待下一个预览。

但我看到它现在已经升级到 preview-9。