Blazor: вторая операция началась в этом контексте до завершения предыдущей операции - PullRequest
0 голосов
/ 11 октября 2019

Я создаю приложение Blazor на стороне сервера. Следующий код находится в Startup.cs.

services.AddDbContext<MyContext>(o => o.UseSqlServer(Configuration.GetConnectionString("MyContext")), ServiceLifetime.Transient);
services.AddTransient<MyViewModel, MyViewModel>();

И в ViewModel:

public class MyViewModel : INotifyPropertyChanged
{
    public MyViewModel(MyContext referenceContext)
    {
        _myContext = myContext;
    }

    public async Task<IEnumerable<Dto>> GetList(string s)
    {
        return await _myContext.Table1.where(....)....ToListAsync();
    }

И в файле бритвы.

@inject ViewModels.MyViewModel VM
<input id="search" type="text" @bind="search" />
<input id="search" type="button" value="Go" @onclick="SearchChanged" />   
@code {
    string search = "";
    int currentCount = 0;
    async void SearchChanged() {
        currentCount++;
        dtos = GetList(search);
    }
}

Однако,иногда при нажатии кнопки поиска возникает следующая ошибка:

System.InvalidOperationException: 'Вторая операция началась в этом контексте до завершения предыдущей операции. Обычно это вызвано тем, что разные потоки используют один и тот же экземпляр DbContext. Для получения дополнительной информации о том, как избежать проблем с многопоточностью с помощью DbContext, см. https://go.microsoft.com/fwlink/?linkid=2097913.'

Ответы [ 2 ]

1 голос
/ 11 октября 2019

Вы можете попытаться создать новую область для каждого запроса:

public class MyViewModel : INotifyPropertyChanged
{

    protected readonly IServiceScopeFactory _ServiceScopeFactory;

    public MyViewModel(IServiceScopeFactory serviceScopeFactory)
    {
        _ServiceScopeFactory = serviceScopeFactory;
    }

    public async Task<IEnumerable<Dto>> GetList(string s)
    {
        using (var scope = _ServiceScopeFactory.CreateScope())
        {
            var referenceContext = scope.ServiceProvider.GetService<MyContext>();    
            return await _myContext.Table1.where(....)....ToListAsync();
        }
    }

Здесь Даниэль Рот (менеджер по продуктам Blazor) говорит о Использование Entity Framework Core с Blazor

0 голосов
/ 11 октября 2019

Сообщение об ошибке связано с тем, что контекст EF не может выполнять более одной операции одновременно.

Насколько я понимаю, если вы находитесь на странице, то у вас есть константаподключение к файлу «Сервис» через соединение SingalR.

Если ваша страница выполняет несколько вызовов Сервиса, возможно, вызывается Контекст для выполнения операции до завершения предыдущегоone.

Вместо того, чтобы иметь один экземпляр Context для срока службы Сервиса, я создал один экземпляр для каждого вызова. Кажется, это смягчает эту проблему, но пока я не уверен, является ли это «лучшей практикой».

Так, например:

public class MyService
{
    private MyContext Context => new MyContext(new DbContextOptions<MyContext>()));

    private async Task DoSomething()
    {
        await using var context = this.Context;  //New context for the lifetime of this method
        var r = await context.Something
            .Where(d => d....)
            .AsNoTracking()
            .FirstOrDefaultAsync()
            .ConfigureAwait(false);

         // context gets disposed of
         // Other code
    }
    private async Task DoSomethingElse()
    {
        await using var context = this.Context;   //New context for the lifetime of this method
        var r = await context.Something
            .Where(d => d....)
            .AsNoTracking()
            .FirstOrDefaultAsync()
            .ConfigureAwait(false);

         // context gets disposed of
         // Other code
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...