entity framework核心:在上一个操作完成之前,在此上下文中启动了第二个操作

我正在使用Entity Framework Core开发ASP.Net Core 2.0项目

   

在我的一个列表方法中,我收到此错误:

 InvalidOperationException: A second operation started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe. Microsoft.EntityFrameworkCore.Internal.ConcurrencyDetector.EnterCriticalSection() 

这是我的方法:

  [HttpGet("{currentPage}/{pageSize}/")] [HttpGet("{currentPage}/{pageSize}/{search}")] public ListResponseVM GetClients([FromRoute] int currentPage, int pageSize, string search) { var resp = new ListResponseVM(); var items = _context.Clients .Include(i => i.Contacts) .Include(i => i.Addresses) .Include("ClientObjectives.Objective") .Include(i => i.Urls) .Include(i => i.Users) .Where(p => string.IsNullOrEmpty(search) || p.CompanyName.Contains(search)) .OrderBy(p => p.CompanyName) .ToPagedList(pageSize, currentPage); resp.NumberOfPages = items.TotalPage; foreach (var item in items) { var client = _mapper.Map(item); client.Addresses = new List(); foreach (var addr in item.Addresses) { var address = _mapper.Map(addr); address.CountryCode = addr.CountryId; client.Addresses.Add(address); } client.Contacts = item.Contacts.Select(p => _mapper.Map(p)).ToList(); client.Urls = item.Urls.Select(p => _mapper.Map(p)).ToList(); client.Objectives = item.Objectives.Select(p => _mapper.Map(p)).ToList(); resp.Items.Add(client); } return resp; } 

我有点迷失,特别是因为它在我本地运行它时有效,但是当我部署到我的登台服务器(IIS 8.5)时,它会让我出现这个错误并且它正常工作。 在我增加一个模型的最大长度后,错误开始出现。 我还更新了相应视图模型的最大长度。 还有许多其他列表方法非常相似,它们正在工作。

我运行了一个Hangfire作业,但是这个作业不使用同一个实体。 这就是我能想到的所有相关内容。 有什么可能导致这个的想法?

该exception意味着_context正被两个线程同时使用; 同一请求中的两个线程,或两个请求。

您的_context是否可以声明为静态? 它不应该。

或者您是否在代码中的其他位置的同一请求中多次调用GetClients

您可能已经这样做了,但理想情况下,您将为DbContext使用dependency injection,这意味着您将在Startup.cs中使用AddDbContext ,并且您的控制器构造函数将如下所示:

  private readonly MyDbContext _context; //not static public MyController(MyDbContext context) { _context = context; } 

如果您的代码不是这样,请告诉我们,也许我们可以提供更多帮助。

我不确定您是否正在使用IoC和dependency injection来解析您可能使用的DbContext。 如果您这样做并且您正在使用.NET Core中的本机IoC,请确保将DbContext注册为Transient。 做

 services.AddTransient(); 

要么

 services.AddDbContext(ServiceLifetime.Transient); 

代替

 services.AddDbContext(); 

AddDbContext将上下文添加为作用域,这可能会在处理多个线程时引起麻烦。

当使用异步lambda表达式时, async / await操作也会导致此行为。

将其添加为瞬态也有其缺点。 您将无法在使用上下文的多个类上对某个实体进行更改,因为每个类都将获得其自己的DbContext实例。

我遇到了同样的问题但原因不在于上面列出的问题。 我创建了一个任务,在任务中创建了一个范围,并要求容器获取服务。 这工作正常,但后来我在任务中使用了第二个服务,我忘了也要求它到新的范围。 因此,第二个服务使用已经处理的DbContext。

  Task task = Task.Run(() => { using (var scope = serviceScopeFactory.CreateScope()) { var otherOfferService = scope.ServiceProvider.GetService(); // everything was ok here. then I did: productService.DoSomething(); // (from the main scope) and this failed because the db context associated to that service was already disposed. ... } } 

我应该这样做:

 var otherProductService = scope.ServiceProvider.GetService(); otherProductService.DoSomething(); 

我只是设法让它再次运作。 它没有多大意义,但它起作用:

  1. 从StartUp中删除Hangfire(我在那里创建我的工作)
  2. 删除了hangfire数据库
  3. 重启服务器

我稍后会进行调查,但是我用hangfire调用的方法会收到一个DBContext,这是可能的原因。