【发布时间】:2021-01-17 16:13:37
【问题描述】:
我搜索了所有有错误解决方案的链接。但是,它们都不适合我,因为我已经有异步代码并且按照他们的建议做了。
我们拥有基于 .NET Core 3.1 的 Azure Functions。我们使用最新版本的 Entity Framework Core。我们间歇性地收到此错误:
System.InvalidOperationException:连接不支持 MultipleActiveResultSets。
在 Microsoft.Data.SqlClient.SqlCommand.c.b__164_0(Task
1 result) at System.Threading.Tasks.ContinuationResultTaskFromResultTask2.InnerInvoke()
在 System.Threading.Tasks.Task.c.<.cctor>b__274_0(Object obj)
在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback 回调, 对象状态)
从先前抛出异常的位置结束堆栈跟踪在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback 回调, 对象状态)
在 System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, 线程 threadPoolThread)
从之前抛出异常的位置结束堆栈跟踪---在 Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancelToken)
在 Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancelToken)
在 Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject 参数对象,CancellationToken 取消令牌) 在 Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable1.AsyncEnumerator.InitializeReaderAsync(DbContext _, Boolean result, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func4 操作,Func4 verifySucceeded, TState state, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func4 操作,Func4 verifySucceeded, TState state, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable1.AsyncEnumerator.MoveNextAsync() 在 Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable1 source, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable1 源,CancellationToken cancelToken)
当我们查看 AppInsights 中的日志时,我们发现异常同时发生,并且对于同一个地方的同一个函数具有完全相同的错误。但是,这是针对三个不同的调用 (InvocationId) 但相同的主机实例 (HostInstanceId) 和不同的操作 Id (操作 ID)。期望是对于每个新的调用,新的 dbContext 将被实例化,因为 AddDbContextPool 默认添加作用域 dbContext 作为依赖项。不确定我们是否可以从中扣除任何东西。
以下是我们的实施方法。感谢您对此的任何帮助。提前致谢。
我们在启动文件中使用以下语句将DbContext 添加到服务中:
builder.Services.AddDbContextPool<OurDbContext>(options =>
{
options.UseSqlServer("connectionstring"), builder =>
{
builder.EnableRetryOnFailure(3, TimeSpan.FromSeconds(2), null);
});
});
OurDbContext 类具有以下构造函数:
public OurDbContext(DbContextOptions<OurDbContext> options)
: base(options)
{
}
然后我们在不同的存储库中注入OurDbContext 类,这些存储库使用此上下文与 SQL 对话。类似于下面:
public class TypesRepo : RepoBase<Types>, ITypesRepo
{
public TypesRepo(OurDbContext ourDbContext) : base(ourDbContext)
{
}
public async Task RetrieveTypesAsync(List<string> types)
{
var records = await RetrieveConditionAsync(x => types.Contains(x.Type));
return records?.Select(x => new { x.Type, x.TypeId })
.ToDictionary(x => x.Type, x => x.TypeId);
}
}
public abstract class RepoBase<T> where T : class
{
protected OurDbContext OurDbContext { get; set; }
public RepoBase(OurDbContext OurDbContext)
{
this.OurDbContext = OurDbContext;
}
public async Task<List<T>> RetrieveConditionAsync(Expression<Func<T, bool>> expression)
{
return await OurDbContext.Set<T>().Where(expression).AsNoTracking().ToListAsync();
}
}
我们在Function类中注入上面的Repo类,调用上面的方法如
await _typesRepo.RetrieveAsync()
P.S.:基于以下评论
我认为 dbcontextpool 将重用 dbcontext 实例,如果它的连接不是活动的/未使用的,但不是活动的。
【问题讨论】:
-
您的代码中是否使用了任何 ContinueWith?你在使用 System.Data.SqlClient nuget,如果是,是哪个版本?我使用不同的方法完成了相同的操作,其中我有一个 ActivityTrigger,它使用过程执行 SQL 逻辑,每天执行大量的操作
-
不,我们的代码中根本没有使用 ContinueWith。 System.Data.SqlClient 都不是 nuget。我们使用实体框架核心 3.1.7,而后者又使用 Microsoft.Data.SqlClient 1.1.3。
-
您是否测试过将
MultipleActiveRecordSets=true;添加到连接字符串中?即使您不想永久使用它,它也会帮助您缩小问题范围。 -
如果关闭上下文池,异常是否总是消失?是否涉及延迟加载?
-
不同请求同时执行时间歇性发生。不涉及延迟加载。我的问题中的 Ctrl c+v,--------------当我们查看 AppInsights 中的日志时,我们发现异常同时发生,并且在一样的地方。但是,它是针对三个不同的调用 (InvocationId) 但相同的主机实例 (HostInstanceId) 和不同的操作 Id (Operation ID)。期望对于每个新的调用,新的 dbContext 将被实例化,因为 AddDbContextPool 默认添加作用域 dbContext 作为依赖项.
标签: .net-core entity-framework-core azure-functions ef-core-3.1