如何在多线程应用程序中使用DbContext

时间:2018-12-22 17:46:11

标签: entity-framework entity-framework-core entity-framework-core-2.1

我有一个以典型方式设置的EF Core网站。效果很好。

但是,我添加了一个Controller Method,它每秒被命中几次,并且当有多个活动线程时,EF会引发异常。如果请求相隔几秒钟,那么它可以正常工作。

我已经尝试调试此功能,但是我看不到我在做什么错。

以下是详细信息:

这些请求来自单个页面应用程序,它们都是相同的连接。如果只有一个请求,则可以正常工作。但是,如果有两个请求,则会引发异常。

  

System.IndexOutOfRangeException     HResult = 0x80131508     Message = Index在数组范围之外。     源= System.Data     堆栈跟踪:      在System.Data.SqlClient.SqlDataReader.CheckHeaderIsReady(Int32 columnIndex,布尔allowAsync,字符串methodName)      在System.Data.SqlClient.SqlDataReader.IsDBNull(Int32 i)      在Microsoft.EntityFrameworkCore.Storage.Internal.TypedRelationalValueBufferFactory.Create(DbDataReader dataReader)      在Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable 1.AsyncEnumerator.<BufferlessMoveNext>d__12.MoveNext() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.<ExecuteImplementationAsync>d__31 2.MoveNext()      在Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.d__31 2.MoveNext() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable 1.AsyncEnumerator.d__11.MoveNext()      在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)      在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)      在Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor 1.EnumeratorExceptionInterceptor.<MoveNext>d__5.MoveNext() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Linq.AsyncEnumerable.<Aggregate_>d__6 3.MoveNext()      在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)      在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)      在System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()      在Traken.Data.Repositories.LookupListItemRepository.d__4.MoveNext()中的C:\ Dev \ Traken.app \ Traken.5 \ Dev \ Traken \ Data \ Repositories \ LookupListItemRepository.cs:第38行

正在使用的存储库:

services.AddScoped<LookupListItemRepository, LookupListItemRepository>();

我也尝试过AddTransient,但遇到相同的错误。

services.AddTransient<LookupListItemRepository, LookupListItemRepository>();

DbContext:

services.AddDbContext<ApplicationDbContext>(optionsBuilder =>
{
                optionsBuilder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
options => options.EnableRetryOnFailure());
});

控制器

[HttpGet("{tableName}")]
public async Task<List<LookupListItem>> GetLookupTableAsync(string tableName) => await this._repository.List(tableName);

存储库

public async Task<List<LookupListItem>> List(string tableName)
{
    return await this._dbContext.LookupTables.FromSql(
                    $@"{SqlStrings.SP.GetLookupTable} 
                    @tableName = {tableName}"
                ).AsNoTracking().ToListAsync();
}

我该如何解决?

1 个答案:

答案 0 :(得分:0)

我通过将存储库设置为AddTransient而不是AddScoped来解决此问题

services.AddTransient<LookupListItemRepository, LookupListItemRepository>();

,并将上下文的生存期设置为Transient

services.AddDbContext<ApplicationDbContext>(optionsBuilder =>
{   optionsBuilder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
        options => options.EnableRetryOnFailure());
}, ServiceLifetime.Transient);

另请参阅:https://docs.microsoft.com/en-us/ef/core/querying/async

public async Task<List<Blog>> GetBlogsAsync()
{
    using (var context = new BloggingContext())
    {
        return await context.Blogs.ToListAsync();
    }
}