Как использовать DbContext в многопоточном приложении - PullRequest
0 голосов
/ 22 декабря 2018

У меня есть веб-сайт EF Core, который настроен обычным способом.Это сработало нормально.

Однако я добавил метод контроллера, который срабатывает несколько раз в секунду, а когда есть несколько активных потоков, EF выдает исключение.Если запросы разнесены на несколько секунд, то все работает нормально.

Я попытался отладить это, но не вижу, что делаю неправильно.

Вот подробности:

Запросы поступают из одностраничного приложения, и все они имеют одинаковое соединение.Если есть только один запрос, он работает нормально.Но если есть два запроса, то генерируется исключение.

System.IndexOutOfRangeException HResult = 0x80131508 Сообщение = Индекс находился за пределами массива.Source = System.Data StackTrace: в System.Data.SqlClient.SqlDataReader.CheckHeaderIsReady (Int32 columnIndex, логическое allowAsync, String methodName) в System.Data.SqlClient.SqlDataReader.IsDBNull (Int32Int.In.F.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.S...Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (задача-задача) в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (задача-задача) в Microsoft.EntityFrameworkCore.Query.Intern.Oun.InceptionCompilerServices.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: line38

Используемый репозиторий:

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 голосов
/ 22 декабря 2018

Я решил эту проблему, установив репозиторий на 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();
    }
}
...