【问题标题】:EF from Task: System.InvalidOperationException: Reader closed [duplicate]来自任务的 EF:System.InvalidOperationException:阅读器已关闭 [重复]
【发布时间】:2018-05-17 19:43:41
【问题描述】:

我正在使用任务在后台发送电子邮件。 尽管生成了 PDF(作为附件包含在邮件中)(GeneratePdf())。我得到以下异常:

下面是调用GetRegistrationOfChild的代码:

编辑 下面是加载dbContext 的代码(Startup.cs,方法ConfigureServices)。然后在构造函数中使用 DI 解决。

services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

【问题讨论】:

  • dbContext 来自哪里?
  • 您实际上并没有向我们展示代码是从哪里调用的,中间缺少的位是这里的关键。您是否在有机会检索数据之前关闭/处置上下文?
  • 我编辑了描述。 dbContext 由构造函数中的 DI 处理。我没有关闭或处置上下文。
  • 当你把它分解成多个查询时会发生什么?
  • dbContext 将在 Web 请求结束时由容器处理。 GeneratePdf 在网络请求之后运行(因为Task.Run),因此在dbContext 被处理之后。您使用的是哪个 IoC 容器?

标签: c# entity-framework .net-core asp.net-core-2.0


【解决方案1】:

实际上,这里有很多问题。您的核心问题可能在 SendRegisterConfirmationAsync 方法中。但是,您尚未提供该方法的代码。如果我不得不猜测,根据错误消息,您正在以非线程安全的方式使用 using 语句。

但是,这也完全有可能是由于异步处理不当造成的。您正在从同步方法调用异步方法。由于 SendEmail 返回 void,您要么吞下了 async 方法的返回值,要么 async 方法是 async void(你应该永远这样做)。在任何一种情况下,由于您不等待异步方法的结果,因此您的其余代码可能会继续使用它。例如,像您的 DbContext 这样的东西是请求范围的,因此如果该异步方法使用您的 DbContext,但在发送响应之前未完成,则上下文将直接从其下方处理,从而导致异常。如果你使用异步,你需要一直异步。

此外,在 Web 应用程序上下文中确实不存在真正的“后台”任务。 Task.Run 只是从处理您的请求的同一个池中拉出另一个线程。你可能允许一个线程返回,但你仍然坐在另一个线程上,所以最好的情况是你什么都没给自己买。最糟糕的情况是,您现在已经有效地将服务器的吞吐量减半,并扼杀了您的扩展能力。

如果您想在后台执行某些操作,请将其卸载到后台进程,即在您的 Web 应用程序的上下文之外。您可以使用 HangfireRevalee 之类的内容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-23
    • 2013-07-09
    • 2017-06-12
    • 2016-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-23
    相关资源
    最近更新 更多