Blazor:在此之前的操作完成之前,在此上下文中开始了第二次操作 [英] Blazor: A second operation started on this context before a previous operation completed

查看:338
本文介绍了Blazor:在此之前的操作完成之前,在此上下文中开始了第二次操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建服务器端Blazor应用程序.以下代码在Startup.cs中.

I'm creating a server side Blazor app. The following code is in the Startup.cs.

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

在ViewModel中:

And in the ViewModel:

public class MyViewModel : INotifyPropertyChanged
{
    public MyViewModel(MyContext myContext)
    {
        _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);
    }
}

但是,有时单击搜索按钮时会发生以下错误?

However, sometimes the following error occur when clicking the search button?

System.InvalidOperationException:'在上一个操作完成之前,第二个操作在此上下文上开始.这通常是由使用相同DbContext实例的不同线程引起的.有关如何避免DbContext线程问题的详细信息,请参阅 https://go.microsoft.com/fwlink/?linkid = 2097913 .'

推荐答案

已编辑 2020年8月

官方指南:

Edited Aug 2020

Official guidance: https://docs.microsoft.com/ca-es/aspnet/core/blazor/blazor-server-ef-core?view=aspnetcore-3.1 with several solutions. In my opinion, the best approach on post is "Create new DbContext instances":

创建具有依赖关系的新DbContext的推荐解决方案是使用工厂.

The recommended solution to create a new DbContext with dependencies is to use a factory.

//The factory
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

namespace BlazorServerDbContextExample.Data
{
    public class DbContextFactory<TContext> 
        : IDbContextFactory<TContext> where TContext : DbContext
    {
        private readonly IServiceProvider provider;

        public DbContextFactory(IServiceProvider provider)
        {
            this.provider = provider;
        }

        public TContext CreateDbContext()
        {
            if (provider == null)
            {
                throw new InvalidOperationException(
                    $"You must configure an instance of IServiceProvider");
            }

            return ActivatorUtilities.CreateInstance<TContext>(provider);
        }
    }
}

注入工厂:

services.AddDbContextFactory<ContactContext>(opt =>
    opt.UseSqlite($"Data Source={nameof(ContactContext.ContactsDb)}.db")
    .EnableSensitiveDataLogging());

使用工厂:

private async Task DeleteContactAsync()
{
    using var context = DbFactory.CreateDbContext();

    Filters.Loading = true;

    var contact = await context.Contacts.FirstAsync(
        c => c.Id == Wrapper.DeleteRequestId);

    if (contact != null)
    {
        context.Contacts.Remove(contact);
        await context.SaveChangesAsync();
    }

    Filters.Loading = false;

    await ReloadAsync();
}


我已弃用的​​答案:

您可以尝试为每个请求创建一个新范围:


My deprecated answer:

You can try to create a new scope for each request:

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();
        }
    }

在以下屏幕截图中,您可以看到此问题的示例案例.用户在几个分页元素中快速单击.新请求开始,之前一个请求结束.

In the following screenshot you can see a sample case of this issue. User clicks quickly in several pagination elements. A new request starts before previous one is ended.

Daniel Roth(Blazor产品经理)在这里谈论在Blazor中使用实体框架核心

Here Daniel Roth (Blazor Product Manager) talking about Using Entity Framework Core with Blazor

这篇关于Blazor:在此之前的操作完成之前,在此上下文中开始了第二次操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆